import AVFoundation
import Foundation

public class VideoRetimeUtility {
    public enum VideoRetimeError: Error {
        case noVideoTrackFound
        case couldNotInsertTrack
    }

    public static func detectFrameRate(_ videoURL: URL) async throws -> Float {
        let asset = AVAsset(url: videoURL)

        if let videoTrack = try await asset.loadTracks(withMediaType: .video).first {
            let frameRate = try await videoTrack.load(.nominalFrameRate)
            return frameRate

        } else {
            throw VideoRetimeError.noVideoTrackFound
        }
    }

    public static func scaleFrameRate(
        of videoURL: URL,
        from originalFPS: Float,
        to targetFPS: Float,
        exportPreset: String = AVAssetExportPresetHEVC1920x1080
    ) async throws -> URL? {
        let original = Int(originalFPS)
        let target = Int(targetFPS)

        guard original != target else { return videoURL }

        let asset = AVAsset(url: videoURL)
        let composition = AVMutableComposition()
        // Ensure there's a video track
        guard
            let videoTrack = try await asset.loadTracks(withMediaType: .video).first,
            let originalDuration = try? await asset.load(.duration)
        else {
            print("Adamantium: no video in first track")
            return nil
        }

        let videoCompositionTrack = composition
            .addMutableTrack(
                withMediaType: .video,
                preferredTrackID: kCMPersistentTrackID_Invalid
            )
        do {
            // Insert the video track into the composition track
            try videoCompositionTrack?.insertTimeRange(
                CMTimeRange(
                    start: .zero,
                    duration: originalDuration
                ),
                of: videoTrack,
                at: .zero
            )
        } catch {
            print("Adamantium: could not insert ")
            throw error
        }
        // Calculate the scale ratio between the original and target frame rates
        let scaleRatio = originalFPS / targetFPS
        // Adjust the video composition track to slow down by the scale ratio
        videoCompositionTrack?.scaleTimeRange(
            CMTimeRange(
                start: .zero,
                duration: originalDuration
            ),
            toDuration: CMTimeMultiplyByFloat64(
                originalDuration,
                multiplier: Double(scaleRatio)
            )
        )
        // Export the composition to a new file
        let exportSession = AVAssetExportSession(
            asset: composition,
            presetName: exportPreset
        )
        exportSession?.outputURL = Adamantium.createRandomFileURLInDocuments("mp4")
        exportSession?.outputFileType = .mp4
        await exportSession?.export()
        if let error = exportSession?.error {
            throw error
        } else {
            return exportSession?.outputURL
        }
    }
}
