import AVFoundation

enum RCTVideoSave {
    static func save(
        options _: NSDictionary!,
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock,

        playerItem: AVPlayerItem?
    ) {
        let asset: AVAsset! = playerItem?.asset

        guard asset != nil else {
            reject("ERROR_ASSET_NIL", "Asset is nil", nil)
            return
        }

        guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {
            reject("ERROR_COULD_NOT_CREATE_EXPORT_SESSION", "Could not create export session", nil)
            return
        }
        var path: String!
        path = RCTVideoSave.generatePathInDirectory(
            directory: URL(fileURLWithPath: RCTVideoSave.cacheDirectoryPath() ?? "").appendingPathComponent("Videos").path,
            withExtension: ".mp4"
        )
        let url: NSURL! = NSURL.fileURL(withPath: path) as NSURL
        exportSession.outputFileType = AVFileType.mp4
        exportSession.outputURL = url as URL?
        exportSession.videoComposition = playerItem?.videoComposition
        exportSession.shouldOptimizeForNetworkUse = true
        exportSession.exportAsynchronously(completionHandler: {
            switch exportSession.status {
            case .failed:
                reject("ERROR_COULD_NOT_EXPORT_VIDEO", "Could not export video", exportSession.error)
            case .cancelled:
                reject("ERROR_EXPORT_SESSION_CANCELLED", "Export session was cancelled", exportSession.error)
            default:
                resolve(["uri": url.absoluteString])
            }
        })
    }

    static func generatePathInDirectory(directory: String?, withExtension extension: String?) -> String? {
        let fileName = UUID().uuidString + (`extension` ?? "")
        RCTVideoSave.ensureDirExists(withPath: directory)
        return URL(fileURLWithPath: directory ?? "").appendingPathComponent(fileName).path
    }

    static func cacheDirectoryPath() -> String? {
        let array = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).map(\.path)
        return array[0]
    }

    static func ensureDirExists(withPath path: String?) -> Bool {
        var isDir: ObjCBool = false
        var error: Error?
        let exists = FileManager.default.fileExists(atPath: path ?? "", isDirectory: &isDir)
        if !(exists && isDir.boolValue) {
            do {
                try FileManager.default.createDirectory(atPath: path ?? "", withIntermediateDirectories: true, attributes: nil)
            } catch {}
            if error != nil {
                return false
            }
        }
        return true
    }
}