import Foundation

public enum AppStartUpError: Error, Equatable {
    case criticalSdkInitFailures([SDKIdentifier])
}

public struct AppStartUpMetrics: Equatable {
    public var startTime: Date?
    public var phaseCompletionTimes: [AppStartUpPhase: Date] = [:]
    public var sdkMetrics: [SDKIdentifier: SDKMetric] = [:]
    public var totalDuration: TimeInterval = 0
    public var errors: [SDKIdentifier: String] = [:]

    public struct SDKMetric: Equatable {
        public let identifier: SDKIdentifier
        public let startTime: Date
        public let endTime: Date?
        public let success: Bool
        public let retryCount: Int
        public let threadName: String

        public var duration: TimeInterval? {
            guard let endTime else { return nil }
            return endTime.timeIntervalSince(startTime)
        }
    }
}

public enum AppStartUpPhase: String, CaseIterable, Equatable {
    case notStarted = "not_started"
    case essential // Firebase only
    case critical // Braze, Clerk, RevenueCat, Statsig
    case important // Others
    case optional // Everything else
    case complete
}

public struct SDKDependency {
    let phase: AppStartUpPhase
    let requirements: [SDKIdentifier]
    let timeout: TimeInterval
    let isOptional: Bool
    let mustBeOnMainThread: Bool

    public init(
        phase: AppStartUpPhase,
        requirements: [SDKIdentifier] = [],
        timeout: TimeInterval = 10.0,
        isOptional: Bool = false,
        mustBeOnMainThread: Bool = false
    ) {
        self.phase = phase
        self.requirements = requirements
        self.timeout = timeout
        self.isOptional = isOptional
        self.mustBeOnMainThread = mustBeOnMainThread
    }
}

public enum SDKIdentifier: String, CaseIterable, Equatable {
    case firebase
    case braze
    case clerk
    case revenueCat = "revenue_cat"
    case statsig
    case adamantium
    case shareAsset = "share_asset"
    case attribution
    case rageshake

    var requiresMainThread: Bool {
        switch self {
        case .firebase:
            return true
        case .braze,
             .clerk,
             .statsig,
             .adamantium,
             .shareAsset,
             .rageshake,
             .revenueCat,
             .attribution:
            return false
        }
    }
}

public enum SDKState: Equatable {
    case notStarted
    case initializing(startTime: Date)
    case completed(duration: TimeInterval)
    case failed(error: String, retryCount: Int)
    case skipped(reason: String)

    var isComplete: Bool {
        switch self {
        case .completed, .skipped: return true
        default: return false
        }
    }

    var isFailed: Bool {
        switch self {
        case .failed: return true
        default: return false
        }
    }
}

#if DEBUG

    // MARK: - Mocks

    extension AppStartUpMetrics {
        static let mock = AppStartUpMetrics(
            startTime: Date(timeIntervalSince1970: 1000),
            phaseCompletionTimes: [
                .essential: Date(timeIntervalSince1970: 1001),
                .critical: Date(timeIntervalSince1970: 1002),
                .complete: Date(timeIntervalSince1970: 1003),
            ],
            sdkMetrics: [
                .firebase: AppStartUpMetrics.SDKMetric(
                    identifier: .firebase,
                    startTime: Date(timeIntervalSince1970: 1000),
                    endTime: Date(timeIntervalSince1970: 1001),
                    success: true,
                    retryCount: 0,
                    threadName: "main"
                ),
            ],
            totalDuration: 3.0,
            errors: [:]
        )
    }
#endif
