import Foundation

public enum VideoCache {
    private static func debugLog(_ message: String) {
        #if DEBUG
            print("[VideoCache Debug]: \(message)")
        #endif
    }

    public static func cleanupOldVideoUploads() {
        Task.detached(priority: .background) {
            debugLog("Starting cleanup...")
            let initialSize = logCacheDirectorySize()
            await cleanupOldVideoUploads()
            cleanupRawVideoAssets()
            let finalSize = logCacheDirectorySize()
            let freedSpace = initialSize - finalSize
            let freedSpaceFormatted = ByteCountFormatter.string(fromByteCount: freedSpace, countStyle: .file)
            debugLog("Cleanup completed. Freed space: \(freedSpaceFormatted).")
        }
    }

    private static func directorySize(url: URL) -> Int64 {
        guard let enumerator = FileManager.default.enumerator(
            at: url,
            includingPropertiesForKeys: [.fileSizeKey],
            options: [.skipsHiddenFiles]
        ) else {
            return 0
        }

        var totalSize: Int64 = 0
        for case let fileURL as URL in enumerator {
            guard let resourceValues = try? fileURL.resourceValues(forKeys: [.fileSizeKey]),
                  let fileSize = resourceValues.fileSize
            else {
                continue
            }
            totalSize += Int64(fileSize)
        }
        return totalSize
    }

    private static func logCacheDirectorySize() -> Int64 {
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return 0
        }
        let size = directorySize(url: cachesDirectory)
        debugLog("Current cache directory size: \(ByteCountFormatter.string(fromByteCount: size, countStyle: .file))")
        return size
    }

    private static func cleanupOldVideoUploads(minFilesToKeep: Int = 1) async {
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return
        }

        do {
            // Get all files in the caches directory
            let fileURLs = try FileManager.default.contentsOfDirectory(
                at: cachesDirectory,
                includingPropertiesForKeys: [.creationDateKey],
                options: .skipsHiddenFiles
            )

            let uploadVideos = fileURLs.filter { $0.lastPathComponent.hasPrefix("video_upload_") }

            let sortedVideos = try uploadVideos.sorted { file1, file2 in
                let date1 = try file1.resourceValues(forKeys: [.creationDateKey]).creationDate ?? .distantPast
                let date2 = try file2.resourceValues(forKeys: [.creationDateKey]).creationDate ?? .distantPast
                return date1 > date2
            }

            debugLog("Video Uploads (oldest first): \(sortedVideos.map { $0.lastPathComponent })")

            // Remove all but the {minFilesToKeep} newest videos
            var numberOfFilesDeletedSuccessfully = 0
            var numberOfFilesFailedToDelete = 0
            if sortedVideos.count > minFilesToKeep {
                for fileURL in sortedVideos[minFilesToKeep...] {
                    do {
                        try FileManager.default.removeItem(at: fileURL)
                        numberOfFilesDeletedSuccessfully += 1
                    } catch {
                        numberOfFilesFailedToDelete += 1
                    }
                }
            }
            debugLog("Successfully deleted \(numberOfFilesDeletedSuccessfully) video uploads")
            debugLog("Failed to delete \(numberOfFilesFailedToDelete) video uploads")
        } catch {
            debugLog("Failed to cleanup old video uploads: \(error)")
        }
    }

    public static func cleanupOldVideoOutputs() {
        Task.detached(priority: .background) {
            await cleanupVideoOutputs()
        }
    }

    // Clears out all videos that begin with "video_output_" that are more than 1 day old
    private static func cleanupVideoOutputs() async {
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return
        }

        do {
            let fileURLs = try FileManager.default.contentsOfDirectory(
                at: cachesDirectory,
                includingPropertiesForKeys: [.creationDateKey],
                options: .skipsHiddenFiles
            )

            let videoOutputs = fileURLs.filter { $0.lastPathComponent.hasPrefix("video_output_") }

            let sortedVideos = try videoOutputs.sorted { file1, file2 in
                let date1 = try file1.resourceValues(forKeys: [.creationDateKey]).creationDate ?? .distantPast
                let date2 = try file2.resourceValues(forKeys: [.creationDateKey]).creationDate ?? .distantPast
                return date1 > date2
            }

            debugLog("Video Outputs (oldest first): \(sortedVideos.map { $0.lastPathComponent })")

            let oneWeekAgo = Date().addingTimeInterval(-86400 * 7) // 60 * 60 * 24 * 7
            var numberOfFilesDeletedSuccessfully = 0
            var numberOfFilesFailedToDelete = 0

            for fileURL in sortedVideos {
                let creationDate = try fileURL.resourceValues(forKeys: [.creationDateKey]).creationDate ?? .distantPast
                if creationDate < oneWeekAgo {
                    do {
                        try FileManager.default.removeItem(at: fileURL)
                        numberOfFilesDeletedSuccessfully += 1
                    } catch {
                        numberOfFilesFailedToDelete += 1
                    }
                }
            }

            debugLog("Successfully deleted \(numberOfFilesDeletedSuccessfully) video outputs")
            debugLog("Failed to delete \(numberOfFilesFailedToDelete) video outputs")
        } catch {
            debugLog("Failed to cleanup old video outputs: \(error)")
        }
    }

    public static func cleanupRawVideoAssets() {
        // Keeping this as an array of assets in case
        // we allow multiple videos per Scene in the future
        let assets = ["trimmedVideo.mp4"]
        guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            return
        }

        do {
            for asset in assets {
                let assetURL = cachesDirectory.appendingPathComponent(asset)
                guard FileManager.default.fileExists(atPath: assetURL.path) else { continue }
                try FileManager.default.removeItem(at: assetURL)
                debugLog("Successfully deleted \(asset)")
            }
        } catch {
            debugLog("Failed to cleanup raw video assets: \(error)")
        }
    }
}
