import StoreKit
import SwiftUI
import Combine

// MARK: - Feature Gate

/// Reiner Value-Type, der den Zugriff auf alle abonnierten Features kapselt.
/// Kann ohne StoreKit in Unit-Tests instanziiert werden.
struct FeatureGate: Equatable {
    let isPro: Bool
    let isMax: Bool

    // MARK: Pro-Features (freigeschaltet durch Pro ODER Max)
    var unlimitedContacts: Bool { isPro }
    var premiumThemes: Bool { isPro }
    var shareExtension: Bool { isPro }

    // MARK: Max-Features (nur durch Max)
    var aiAnalysis: Bool { isMax }
    var giftSuggestions: Bool { isMax }
    var conversationTopics: Bool { isMax }
    var unlimitedAIQueries: Bool { isMax }

    /// Invariante: Max schließt immer alle Pro-Features ein.
    var isConsistent: Bool { !isMax || isPro }

    /// Erstellt FeatureGate aus dem Ergebnis eines Transaktions-Scans.
    /// Max setzt automatisch auch isPro = true.
    static func from(foundPro: Bool, foundMax: Bool) -> FeatureGate {
        FeatureGate(isPro: foundPro || foundMax, isMax: foundMax)
    }

    static let free = FeatureGate(isPro: false, isMax: false)

    // MARK: - Hilfsfunktionen (Pure Logic, testbar)

    /// Darf die KI genutzt werden? Max-Abonnenten immer, sonst nur wenn noch Gratis-Abfragen übrig.
    static func canUseAI(isMax: Bool, hasFreeQueriesLeft: Bool) -> Bool {
        isMax || hasFreeQueriesLeft
    }

    /// Soll eine Gratis-Abfrage verbraucht werden? Nur bei Nicht-Max-Abonnenten.
    static func shouldConsumeFreeQuery(isMax: Bool) -> Bool {
        !isMax
    }
}

// MARK: - Subscription Tier

enum SubscriptionTier: CaseIterable {
    case pro, max

    var productID: String {
        switch self {
        case .pro: return "profeatures"
        case .max: return "maxfeatures"
        }
    }

    var displayName: String {
        switch self {
        case .pro: return "Pro"
        case .max: return "Max"
        }
    }
}

// MARK: - StoreManager

@MainActor
class StoreManager: ObservableObject {
    static let shared = StoreManager()

    /// Wahr wenn Pro ODER Max aktiv — steuert Kontaktlimit, Themes, Teilen-Extension
    @Published private(set) var isPro: Bool = false
    /// Wahr nur wenn Max aktiv — steuert KI-Analyse & Geschenkideen
    @Published private(set) var isMax: Bool = false

    @Published private(set) var proProduct: Product? = nil
    @Published private(set) var maxProduct: Product? = nil
    @Published private(set) var purchaseError: String? = nil

    /// Rückwärtskompatibilität für bestehende Aufrufstellen
    var product: Product? { proProduct }

    /// Aktueller Feature-Zustand als testbarer Value-Type.
    var features: FeatureGate { FeatureGate(isPro: isPro, isMax: isMax) }

    private var transactionListenerTask: Task<Void, Never>? = nil

    private init() {
        transactionListenerTask = listenForTransactions()
        Task { await loadProducts() }
        Task { await refreshStatus() }
    }

    deinit {
        transactionListenerTask?.cancel()
    }

    // MARK: - Produkte laden

    func loadProducts() async {
        do {
            let ids = SubscriptionTier.allCases.map { $0.productID }
            let products = try await Product.products(for: ids)
            proProduct = products.first { $0.id == SubscriptionTier.pro.productID }
            maxProduct = products.first { $0.id == SubscriptionTier.max.productID }
        } catch {}
    }

    // MARK: - Kauf

    func purchase(tier: SubscriptionTier) async {
        let current = tier == .pro ? proProduct : maxProduct
        if current == nil { await loadProducts() }
        guard let product = (tier == .pro ? proProduct : maxProduct) else {
            purchaseError = "Produkt konnte nicht geladen werden. Bitte Internetverbindung prüfen."
            return
        }
        purchaseError = nil
        do {
            let result = try await product.purchase()
            switch result {
            case .success(let verification):
                if case .verified(let transaction) = verification {
                    await transaction.finish()
                    await refreshStatus()
                }
            case .userCancelled:
                break
            case .pending:
                break
            @unknown default:
                break
            }
        } catch {
            purchaseError = error.localizedDescription
        }
    }

    // MARK: - Wiederherstellen

    func restorePurchases() async {
        do {
            try await AppStore.sync()
            await refreshStatus()
        } catch {
            purchaseError = error.localizedDescription
        }
    }

    // MARK: - Status

    func refreshStatus() async {
        var foundPro = false
        var foundMax = false
        for await result in Transaction.currentEntitlements {
            if case .verified(let transaction) = result,
               transaction.revocationDate == nil {
                switch transaction.productID {
                case SubscriptionTier.pro.productID: foundPro = true
                case SubscriptionTier.max.productID: foundMax = true
                default: break
                }
            }
        }
        let gate = FeatureGate.from(foundPro: foundPro, foundMax: foundMax)
        isMax = gate.isMax
        isPro = gate.isPro
        AppGroup.saveProStatus(isPro)
    }

    // MARK: - Transaction Listener

    private func listenForTransactions() -> Task<Void, Never> {
        Task(priority: .background) {
            for await result in Transaction.updates {
                if case .verified(let transaction) = result {
                    await transaction.finish()
                    await refreshStatus()
                }
            }
        }
    }
}
