import Foundation
import AVFoundation

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
        }
    }
}
