import Foundation
import StoreKit

@MainActor
final class IAPManager: ObservableObject {
    @Published var isPurchasing: Bool = false
    @Published var pioneerProduct: Product?
    @Published var errorMessage: String?
    @Published var isSubscribed: Bool = false
    @Published var subscriptionExpiry: Date? = nil

    // Product IDs from App Store Connect
    private let productIDs: [String] = [
        "MEMBERSHIP_PIONEER_MONTHLY"
    ]

    init() {
        Task { await observeTransactions() }
    }

    // Load products defined in App Store Connect
    func loadProducts() async {
        do {
            let products = try await Product.products(for: productIDs)
            // You can refine selection logic if you have multiple tiers
            self.pioneerProduct = products.first
            if products.isEmpty {
                // No products found is a common setup issue (App Store Connect, StoreKit config, or bundle ID)
                self.errorMessage = "No subscription products found. Please try again later."
            }
        } catch {
            self.errorMessage = "Failed to load products: \(error.localizedDescription)"
        }
    }

    // Trigger App Store purchase sheet
    func purchasePioneer() async {
        guard !isPurchasing else { return }
        guard let product = pioneerProduct else {
            // Surface an actionable error so the UI can inform the user
            self.errorMessage = "Subscription product unavailable. Please try again later."
            return
        }
        isPurchasing = true
        defer { isPurchasing = false }

        do {
            let result = try await product.purchase()
            switch result {
            case .success(let verification):
                switch verification {
                case .unverified(_, let error):
                    self.errorMessage = "Purchase unverified: \(error.localizedDescription)"
                case .verified(let transaction):
                    // Update entitlement for the purchased product
                    updateEntitlement(from: transaction)
                    await transaction.finish()
                }
            case .userCancelled:
                break
            case .pending:
                break
            @unknown default:
                break
            }
        } catch {
            self.errorMessage = "Purchase failed: \(error.localizedDescription)"
        }
    }

    // Restore purchases (sync entitlements)
    func restorePurchases() async {
        do {
            try await AppStore.sync()
        } catch {
            self.errorMessage = "Restore failed: \(error.localizedDescription)"
        }
    }

    // Observe transaction updates for entitlement changes
    private func observeTransactions() async {
        for await result in Transaction.updates {
            do {
                let transaction: Transaction = try checkVerified(result)
                // Update entitlement state for transaction.productID
                updateEntitlement(from: transaction)
                await transaction.finish()
            } catch {
                // Ignore unverified transactions
            }
        }
    }

    // Check current entitlements (useful on launch)
    func refreshEntitlements() async {
        for await result in Transaction.currentEntitlements {
            if case .verified(let transaction) = result,
               productIDs.contains(transaction.productID) {
                updateEntitlement(from: transaction)
            }
        }
    }

    // Helper: verify
    private func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
        switch result {
        case .unverified(_, let error):
            throw error
        case .verified(let safe):
            return safe
        }
    }

    private func updateEntitlement(from transaction: Transaction) {
        guard productIDs.contains(transaction.productID) else { return }
        // For auto-renewable subs, use expirationDate and revocationDate
        if transaction.revocationDate == nil {
            self.isSubscribed = true
            self.subscriptionExpiry = transaction.expirationDate
        } else {
            self.isSubscribed = false
            self.subscriptionExpiry = nil
        }
    }
}
