import ComposableArchitecture
import Foundation
import RealFlags
import Statsig

public protocol SunoStatsigParameterStore: FlagCollectionProtocol {
    /// Match the parameter store name in the Statsig dashoard exactly
    static var parameterStoreName: String { get }
}

public extension SunoStatsigParameterStore {
    static var loader: FlagsLoader<Self> {
        FlagsLoader(Self.self, providers: [
            localOverridingProvider(),
            StatsigRemoteProvider(statSigCollectionName: parameterStoreName),
        ])
    }

    static func markExposed<F: FlagProtocol>(flag: KeyPath<Self, Flag<F>>) {
        @Dependency(StatsigClient.self) var statsigClient
        let flagValue = Self()[keyPath: flag]
        statsigClient.markExposure(
            parameterStore: Self.parameterStoreName,
            key: flagValue.fixedKey,
            defaultValue: flagValue.defaultValue as! StatsigDynamicConfigValue
        )
    }
}

private let applicationSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
public extension SunoStatsigParameterStore {
    static func localOverridingProvider() -> LocalProvider {
        let fileName = "\(parameterStoreName)_localflags.json"

        if let applicationSupportDirectory = applicationSupportDirectory {
            return LocalProvider(localURL: applicationSupportDirectory.appendingPathComponent(fileName))
        } else {
            assertionFailure("couldn't construct application support directory URL")
            return LocalProvider()
        }
    }
}

private class StatsigRemoteProvider: FlagsProvider {
    var name: String {
        "Statsig \(statSigCollectionName)"
    }

    let shortDescription: String? = .none
    let isWritable: Bool = false

    private let statSigCollectionName: String
    @Dependency(StatsigClient.self) private var statsigClient

    init(statSigCollectionName: String) {
        self.statSigCollectionName = statSigCollectionName
    }

    func setValue<Value>(_: Value?, forFlag _: RealFlags.FlagKeyPath) throws -> Bool where Value: RealFlags.FlagProtocol {
        false // Not supported on Statsig
    }

    func resetValueForFlag(key _: RealFlags.FlagKeyPath) throws {
        // Not supported on Statsig
    }

    func valueForFlag<Value>(key: FlagKeyPath, defaultValueHint: Value) -> Value? where Value: FlagProtocol {
        statsigClient.getValue(
            parameterStore: statSigCollectionName,
            key: key.fullPath,
            defaultValue: defaultValueHint as! StatsigDynamicConfigValue
        ) as? Value
    }
}
