import Foundation
import RevenueCat

// MARK: - Billing Service

final class BillingService: @unchecked Sendable {
    static let shared = BillingService()
    
    private var isConfigured = false
    private var customerInfoListener: Task<Void, Never>?
    
    private init() {}
    
    func configure(with apiKey: String) {
        guard !isConfigured else { return }
        #if DEBUG
        Purchases.logLevel = .debug
        #else
        Purchases.logLevel = .warn
        #endif
        Purchases.configure(withAPIKey: apiKey)
        isConfigured = true
    }
    
    /// Fetch available offerings for the paywall
    func getOfferings() async throws -> Offerings {
        try await Purchases.shared.offerings()
    }
    
    /// Purchase a package
    func purchase(_ package: Package) async throws {
        let result = try await Purchases.shared.purchase(package: package)
        // After successful purchase, sync entitlement with server
        try await FirestoreService.shared.syncEntitlementCallable()
    }
    
    /// Purchase the first package from the current offering
    func purchase() async throws -> CustomerInfo {
        let offerings = try await getOfferings()
        guard let package = offerings.current?.availablePackages.first else {
            throw BillingError.noAvailablePackage
        }
        let result = try await Purchases.shared.purchase(package: package)
        try await FirestoreService.shared.syncEntitlementCallable()
        return result.customerInfo
    }
    
    /// Restore previous purchases
    func restorePurchases() async throws -> CustomerInfo {
        try await Purchases.shared.restorePurchases()
    }
    
    /// Reactive stream of customer info
    var customerInfoStream: AsyncStream<CustomerInfo> {
        AsyncStream { continuation in
            let task = Task {
                for await info in Purchases.shared.customerInfoStream {
                    continuation.yield(info)
                }
            }
            continuation.onTermination = { _ in task.cancel() }
        }
    }
    
    /// Check if current user has premium entitlement
    func checkPremiumStatus() async -> Bool {
        do {
            let customerInfo = try await Purchases.shared.customerInfo()
            return customerInfo.entitlements["closer_premium"]?.isActive == true
        } catch {
            return false
        }
    }
}

// MARK: - Entitlement Checking

protocol EntitlementChecking: Actor {
    var isPremium: AsyncStream<Bool> { get }
    func hasPremium() async -> Bool
}

final actor DefaultEntitlementChecker: EntitlementChecking {
    nonisolated let isPremium: AsyncStream<Bool>
    private let billing: BillingService
    private let firestore: FirestoreService
    
    init(billing: BillingService = .shared, firestore: FirestoreService = .shared) {
        self.billing = billing
        self.firestore = firestore
        
        // Create async stream combining RevenueCat + Firestore
        self.isPremium = AsyncStream { continuation in
            let task = Task {
                // Listen to RevenueCat changes
                for await _ in billing.customerInfoStream {
                    let premium = await billing.checkPremiumStatus()
                    continuation.yield(premium)
                }
            }
            continuation.onTermination = { _ in task.cancel() }
        }
    }
    
    func hasPremium() async -> Bool {
        await billing.checkPremiumStatus()
    }
}

// MARK: - Billing Errors

enum BillingError: LocalizedError {
    case noAvailablePackage
    
    var errorDescription: String? {
        switch self {
        case .noAvailablePackage:
            return "No purchase package is currently available."
        }
    }
}