import AVFoundation
import UIKit

enum VideoRotator {
    enum VideoRotatorError: Error {
        case internalError
    }

    static func rotatePortraitToLandscape(inputURL: URL, isFlipped: Bool) async -> Result<URL, Error> {
        let asset = AVAsset(url: inputURL)

        // 1. Create composition and insert video track
        let composition = AVMutableComposition()
        guard
            let duration = try? await asset.load(.duration),
            let videoTrack = try? await asset.loadTracks(withMediaType: .video).first,
            let naturalSize = try? await videoTrack.load(.naturalSize),
            let compositionTrack = composition.addMutableTrack(withMediaType: .video,
                                                               preferredTrackID: kCMPersistentTrackID_Invalid)
        else {
            return .failure(NSError(domain: "VideoRotator", code: -1, userInfo: [NSLocalizedDescriptionKey: "Video track not found."]))
        }

        do {
            try compositionTrack.insertTimeRange(
                CMTimeRange(start: .zero, duration: duration),
                of: videoTrack,
                at: .zero
            )
        } catch {
            return .failure(error)
        }

        // 2. Create transform instruction to rotate & scale into landscape
        // Completely separate transform paths for flipped and non-flipped
        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRange(start: .zero, duration: duration)

        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compositionTrack)

        let renderSize = CGSize(width: 1080, height: 1920)

        var transform: CGAffineTransform

        if isFlipped {
            // For front camera, rotate 90° COUNTER-clockwise
            transform = CGAffineTransform(a: 0, b: -1, c: 1, d: 0, tx: 0, ty: naturalSize.width)
        } else {
            // For back camera (not flipped)
            transform = CGAffineTransform(a: 0, b: 1, c: -1, d: 0, tx: naturalSize.height, ty: 0)
        }

        // Scale and center (same for both cases)
        let scale = min(renderSize.width / naturalSize.height,
                        renderSize.height / naturalSize.width)
        transform = transform.scaledBy(x: scale, y: scale)

        let offsetX = (renderSize.width - naturalSize.height * scale) / 2
        let offsetY = (renderSize.height - naturalSize.width * scale) / 2
        transform = transform.translatedBy(x: offsetX / scale, y: offsetY / scale)

        layerInstruction.setTransform(transform, at: .zero)
        instruction.layerInstructions = [layerInstruction]

        let videoComposition = AVMutableVideoComposition()
        videoComposition.instructions = [instruction]
        videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
        videoComposition.renderSize = renderSize

        // 4. Export session
        let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("rotated_output.mov")
        try? FileManager.default.removeItem(at: outputURL)

        guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
            return .failure(NSError(domain: "VideoRotator", code: -2, userInfo: [NSLocalizedDescriptionKey: "Could not create export session."]))
        }

        do {
            exportSession.videoComposition = videoComposition
            if #available(iOS 18, *) {
                try await exportSession.export(to: outputURL, as: .mov)
            } else {
                exportSession.outputURL = outputURL
                exportSession.outputFileType = .mov
                await exportSession.export()
            }

            switch exportSession.status {
            case .completed:
                return .success(outputURL)

            case .failed, .cancelled:
                let error = exportSession.error ?? NSError(
                    domain: "VideoRotator",
                    code: -3,
                    userInfo: [NSLocalizedDescriptionKey: "Unknown export error."]
                )
                return .failure(error)

            default:
                return .failure(VideoRotatorError.internalError)
            }
        } catch {
            return .failure(error)
        }
    }
}
