import Foundation

// TODO: After scenes is fully deprecated, this file can be removed
public extension Clip {
    var playableSceneUrl: URL? {
        var url: URL?

        if let videoUrlString = self.videoToSongVideoOutputUrl,
           let videoUrl = URL(string: videoUrlString)
        {
            url = videoUrl
        }

        if let lastPathComponent = url?.lastPathComponent,
           let cachedUrl = getCachedVideoUrl(for: lastPathComponent)
        {
            return cachedUrl
        }

        // Check for corrupted file from video composition
        // This is only used if `Me` is the creator
        let generatedFileName = "video_output_\(self.id.remoteId).mp4"
        if let cachedUrl = getCachedVideoUrl(for: generatedFileName),
           validateCachedFile(at: cachedUrl)
        {
            return cachedUrl
        }

        return url
    }

    func downloadableShortUrl() async throws -> URL {
        // Checks if we have a Scene that's cached
        // and not streaming from CDN
        if let playableSceneUrl, playableSceneUrl.isFileURL {
            return playableSceneUrl
        }

        guard let videoUrlString = self.videoToSongVideoOutputUrl,
              let videoUrl = URL(string: videoUrlString)
        else {
            throw ClipVideoError.invalidURL
        }

        return try await downloadAndCacheFile(from: videoUrl)
    }

    private func getCachedVideoUrl(for fileName: String) -> URL? {
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return nil
        }

        let cachedFilePath = cachesDirectory.appendingPathComponent(fileName)

        guard FileManager.default.fileExists(atPath: cachedFilePath.path) else {
            return nil
        }

        return cachedFilePath
    }

    private func downloadAndCacheFile(from url: URL) async throws -> URL {
        let (localUrl, _) = try await URLSession.shared.download(from: url)
        return try cacheDownloadedFile(from: localUrl, originalUrl: url)
    }

    private func cacheDownloadedFile(from localUrl: URL, originalUrl: URL) throws -> URL {
        let fileName = originalUrl.lastPathComponent
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            throw ClipVideoError.cacheError
        }

        let cachedFilePath = cachesDirectory.appendingPathComponent(fileName)

        if FileManager.default.fileExists(atPath: cachedFilePath.path) {
            try FileManager.default.removeItem(at: cachedFilePath)
        }
        try FileManager.default.copyItem(at: localUrl, to: cachedFilePath)

        return cachedFilePath
    }

    private func validateCachedFile(at url: URL) -> Bool {
        guard let attributes = try? FileManager.default.attributesOfItem(atPath: url.path),
              let fileSize = attributes[FileAttributeKey.size] as? UInt,
              fileSize > 0 && url.pathExtension.lowercased() == "mp4"
        else {
            return false
        }
        return true
    }

    private enum ClipVideoError: Error {
        case invalidURL
        case cacheError
    }
}
