import Adamantium
import Foundation

public enum AdamantiumAppResource: String, CaseIterable {
    enum ResourceError: Error {
        case renderResourceError
    }

    /**
         Is array so that assets are rendered in this order
         In order of importance and usage; most usage first
         least usage later
     */

    static var includedAppResourceSet: [AdamantiumAppResource] {
        return [
            .videoAuraLoopPurpleOrangeV1,
            .videoAuraLoopRedOrangeYellowV1,
            .videoAuraLoopPinkBlueTanV1,
        ]
    }

    /**
        These will be included as filenames inside of the Adamantium Cache
     */
    case videoAuraLoopPurpleOrangeV1
    case videoAuraLoopRedOrangeYellowV1
    case videoAuraLoopPinkBlueTanV1

    var cacheKey: AdamantiumResourceCache.CacheKey {
        switch self {
        case .videoAuraLoopPurpleOrangeV1,
             .videoAuraLoopRedOrangeYellowV1,
             .videoAuraLoopPinkBlueTanV1:
            return .init(rawValue, type: .mp4)
        }
    }

    func getResource(_ cache: AdamantiumResourceCache)
    async throws -> (URL, AdamantiumResourceCache.ResourceRerenderedState) {
        return try await cache.getCachedFile(for: cacheKey, orCreateResource: createResource)
    }

    static func setupCacheIfNeeded(_ cache: AdamantiumResourceCache) async throws {
        do {
            guard let cacheParentURL else { return }
            let keysExcludedFromClear = Set(includedAppResourceSet.map { $0.cacheKey })

            /**
                The intention behind this order of steps:

                - Setting root directory is used in all later steps
                - Setting up adamantium resource cache directory if needed
                  which is where the persisted cache resources will be located;
                  Nothing will happen if the directory already exists.
                - Clear cache: Delete all files that are no longer needed in the
                  resource cache.
                - Validate or create resource as needed; If for some reason the resource
                  is missing at this step then it will be generated.
             */
            cache.setRootDirectory(cacheParentURL)
            try cache.setupAdamantiumResourceCacheIfNeeded()
            try cache.clearCache(exclude: keysExcludedFromClear)

            // Validate or render resource as needed
            for resourceCase in includedAppResourceSet {
                let (resourceURL, renderStatus) = try await resourceCase.getResource(cache)
                switch renderStatus {
                case .foundValidResource:
                    log.debug("✅ Valid Adamantium Resource Cache Item \(resourceURL.lastPathComponent)")
                case .rerenderedResource:
                    log.debug("⏺️ Rendered Adamantium Resource Cache Item \(resourceURL.lastPathComponent)")
                }
            }
        } catch {
            log.error("Failed to set up cache: \(error.localizedDescription)")
        }
    }
}

private extension AdamantiumAppResource {
    static var cacheParentURL: URL? {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
    }

    func createResource() async throws -> URL {
        var colorSet: SunoTriColorSet {
            switch self {
            case .videoAuraLoopPurpleOrangeV1:
                return .custom(
                    .custom(0.129411764705882, 0.098039215686275, 0.474509803921569),
                    .custom(0.435294117647059, 0.098039215686275, 0.631372549019608),
                    .custom(0.647058823529412, 0.270588235294118, 0.356862745098039)
                )

            case .videoAuraLoopRedOrangeYellowV1:
                return .custom(
                    .custom(0.71625406, 0.31341183, 0.3486666),
                    .custom(0.44672716, 0.018926017, 0.35154408),
                    .custom(0.75599444, 0.44785076, 0.21935332)
                )

            case .videoAuraLoopPinkBlueTanV1:
                return .custom(
                    .custom(0.7332184, 0.32922333, 0.11966384),
                    .custom(0.58820355, 0.81534046, 1.018426),
                    .custom(0.74338776, 0.68420535, 0.8769395)
                )
            }
        }

        /**
            Switch is here to account for other types of resource generation.
            It is reasonable to assume this will include image generation in the future
         */
        switch self {
        case .videoAuraLoopPinkBlueTanV1,
             .videoAuraLoopPurpleOrangeV1,
             .videoAuraLoopRedOrangeYellowV1:
            // 30 seconds is the default value but adding it here for clarity
            return try await AdamantiumPresetAuraVideoRender
                .renderAuraVideoLoop(colorSet, duration: 30.0)
        }
    }
}
