import Foundation
import StoreKit
import ComposeApp

/// StoreKit 2 manager for in-app purchases
/// Handles product loading, purchases, transaction observation, and backend verification
@MainActor
class StoreKitManager: ObservableObject {
    static let shared = StoreKitManager()

    // Product IDs can be configured via Info.plist keys:
    // HONEYDUE_IAP_MONTHLY_PRODUCT_ID / HONEYDUE_IAP_ANNUAL_PRODUCT_ID.
    // Falls back to local StoreKit config IDs for development.
    // Canonical source: SubscriptionProducts in commonMain (Kotlin shared code).
    // Keep these in sync with SubscriptionProducts.MONTHLY / SubscriptionProducts.ANNUAL.
    private let fallbackProductIDs = [
        "com.tt.honeyDue.pro.monthly",
        "com.tt.honeyDue.pro.annual"
    ]

    private var configuredProductIDs: [String] {
        let monthly = Bundle.main.object(forInfoDictionaryKey: "HONEYDUE_IAP_MONTHLY_PRODUCT_ID") as? String
        let annual = Bundle.main.object(forInfoDictionaryKey: "HONEYDUE_IAP_ANNUAL_PRODUCT_ID") as? String
        return [monthly, annual]
            .compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }
    }

    private var productIDs: [String] {
        if configuredProductIDs.isEmpty {
            return fallbackProductIDs
        }
        return configuredProductIDs
    }

    @Published var products: [Product] = []
    @Published var purchasedProductIDs: Set<String> = []
    @Published var isLoading = false
    @Published var purchaseError: String?

    private var transactionListener: Task<Void, Error>?

    private init() {
        // Start listening for transactions
        transactionListener = listenForTransactions()

        // Check for existing entitlements
        Task {
            await updatePurchasedProducts()
        }
    }

    deinit {
        transactionListener?.cancel()
    }

    /// Load available products from App Store
    func loadProducts() async {
        isLoading = true
        defer { isLoading = false }

        do {
            if configuredProductIDs.isEmpty {
                print("⚠️ StoreKit: Using fallback product IDs (configure HONEYDUE_IAP_MONTHLY_PRODUCT_ID/HONEYDUE_IAP_ANNUAL_PRODUCT_ID in Info.plist for production)")
            }
            let loadedProducts = try await Product.products(for: productIDs)
            products = loadedProducts.sorted { $0.price < $1.price }
            print("✅ StoreKit: Loaded \(products.count) products")
        } catch {
            print("❌ StoreKit: Failed to load products: \(error)")
            purchaseError = "Failed to load products: \(error.localizedDescription)"
        }
    }

    /// Purchase a product
    func purchase(_ product: Product) async throws -> Transaction? {
        print("🛒 StoreKit: Initiating purchase for \(product.id)")

        // Start the purchase
        let result = try await product.purchase()

        switch result {
        case .success(let verification):
            // Verify the transaction
            let transaction = try checkVerified(verification)

            // Update purchased products
            await updatePurchasedProducts()

            // Verify with backend — only finish the transaction if verification succeeds
            do {
                try await verifyTransactionWithBackend(transaction)
                await transaction.finish()
                print("✅ StoreKit: Purchase successful for \(product.id)")
            } catch {
                print("⚠️ StoreKit: Backend verification failed for \(product.id), transaction NOT finished so it can be retried: \(error)")
                self.purchaseError = "Purchase successful but verification is pending. It will complete automatically."
            }

            return transaction

        case .userCancelled:
            print("⚠️ StoreKit: User cancelled purchase")
            return nil

        case .pending:
            print("⏳ StoreKit: Purchase pending (requires approval)")
            return nil

        @unknown default:
            print("❌ StoreKit: Unknown purchase result")
            return nil
        }
    }

    /// Restore previous purchases
    func restorePurchases() async {
        print("🔄 StoreKit: Restoring purchases")

        do {
            // Sync with App Store
            try await AppStore.sync()

            // Update purchased products
            await updatePurchasedProducts()

            // Verify all current entitlements with backend
            for await result in Transaction.currentEntitlements {
                let transaction = try checkVerified(result)
                try await verifyTransactionWithBackend(transaction)
            }

            print("✅ StoreKit: Purchases restored")
        } catch {
            print("❌ StoreKit: Failed to restore purchases: \(error)")
            purchaseError = "Failed to restore purchases: \(error.localizedDescription)"
        }
    }

    /// Check if user has an active subscription
    func hasActiveSubscription() async -> Bool {
        // Check current entitlements
        for await result in Transaction.currentEntitlements {
            if let transaction = try? checkVerified(result),
               transaction.productType == .autoRenewable,
               !transaction.isUpgraded {
                return true
            }
        }
        return false
    }

    /// Refresh subscription status from StoreKit
    /// Call this when app comes to foreground to ensure we have latest status
    func refreshSubscriptionStatus() async {
        await updatePurchasedProducts()
        print("🔄 StoreKit: Subscription status refreshed")
    }

    /// Verify current entitlements with backend on app launch
    /// This ensures the backend has up-to-date subscription info
    func verifyEntitlementsOnLaunch() async {
        print("🔄 StoreKit: Verifying entitlements on launch...")

        // Get current entitlements from StoreKit
        for await result in Transaction.currentEntitlements {
            guard case .verified(let transaction) = result else {
                continue
            }

            // Skip if revoked
            if transaction.revocationDate != nil {
                continue
            }

            // Only process subscription products
            if transaction.productType == .autoRenewable {
                print("📦 StoreKit: Found active subscription: \(transaction.productID)")

                // Verify this transaction with backend (best-effort on launch)
                do {
                    try await verifyTransactionWithBackend(transaction)
                } catch {
                    print("⚠️ StoreKit: Backend verification failed on launch for \(transaction.productID): \(error)")
                }

                // Update local purchased products
                _ = purchasedProductIDs.insert(transaction.productID)
            }
        }

        // After verifying all entitlements, refresh subscription status from backend
        await refreshSubscriptionFromBackend()

        print("✅ StoreKit: Launch verification complete")
    }

    /// Fetch latest subscription status from backend and update cache
    private func refreshSubscriptionFromBackend() async {
        do {
            let statusResult = try await APILayer.shared.getSubscriptionStatus(forceRefresh: true)

            if let statusSuccess = statusResult as? ApiResultSuccess<ComposeApp.SubscriptionStatus>,
               let subscription = statusSuccess.data {
                SubscriptionCacheWrapper.shared.updateSubscription(subscription)
                print("✅ StoreKit: Backend subscription status updated - Tier: \(subscription.limits)")
            }
        } catch {
            print("❌ StoreKit: Failed to refresh subscription from backend: \(error)")
        }
    }

    /// Update purchased product IDs
    private func updatePurchasedProducts() async {
        var purchasedIDs: Set<String> = []

        // Iterate through all current entitlements
        for await result in Transaction.currentEntitlements {
            guard case .verified(let transaction) = result else {
                continue
            }

            // Add to purchased set if not revoked or expired
            if transaction.revocationDate == nil {
                purchasedIDs.insert(transaction.productID)
            }
        }

        purchasedProductIDs = purchasedIDs
        print("📦 StoreKit: Updated purchased products: \(purchasedIDs)")
    }

    /// Listen for transaction updates
    private func listenForTransactions() -> Task<Void, Error> {
        return Task {
            for await result in Transaction.updates {
                do {
                    let transaction = try checkVerified(result)

                    await updatePurchasedProducts()

                    do {
                        try await verifyTransactionWithBackend(transaction)
                        await transaction.finish()
                        print("✅ StoreKit: Transaction updated: \(transaction.productID)")
                    } catch {
                        print("⚠️ StoreKit: Backend verification failed for \(transaction.productID), transaction NOT finished so it can be retried: \(error)")
                    }
                } catch {
                    print("❌ StoreKit: Transaction verification failed: \(error)")
                }
            }
        }
    }

    /// Verify transaction with backend API
    /// Throws if backend verification fails so callers can decide whether to finish the transaction
    private func verifyTransactionWithBackend(_ transaction: Transaction) async throws {
        let receiptData = String(transaction.id)

        // Call backend verification endpoint via APILayer
        let result = try await APILayer.shared.verifyIOSReceipt(
            receiptData: receiptData,
            transactionId: String(transaction.id)
        )

        // Handle result (Kotlin ApiResult type)
        if let successResult = result as? ApiResultSuccess<VerificationResponse>,
           let response = successResult.data,
           response.success {
            print("✅ StoreKit: Backend verification successful - Tier: \(response.tier ?? "unknown")")

            // Fetch updated subscription status from backend via APILayer
            let statusResult = try await APILayer.shared.getSubscriptionStatus(forceRefresh: true)

            if let statusSuccess = statusResult as? ApiResultSuccess<ComposeApp.SubscriptionStatus>,
               let subscription = statusSuccess.data {
                SubscriptionCacheWrapper.shared.updateSubscription(subscription)
            }
        } else if let errorResult = ApiResultBridge.error(from: result) {
            let message = errorResult.message
            print("❌ StoreKit: Backend verification failed: \(message)")
            throw StoreKitError.backendVerificationFailed(message)
        } else if let successResult = result as? ApiResultSuccess<VerificationResponse>,
                  let response = successResult.data,
                  !response.success {
            let message = response.message
            print("❌ StoreKit: Backend verification failed: \(message)")
            throw StoreKitError.backendVerificationFailed(message)
        }
    }

    /// Verify the cryptographic signature of a transaction
    private func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
        switch result {
        case .unverified:
            throw StoreKitError.verificationFailed
        case .verified(let safe):
            return safe
        }
    }
}

// MARK: - StoreKit Errors
extension StoreKitManager {
    enum StoreKitError: LocalizedError {
        case verificationFailed
        case noProducts
        case purchaseFailed
        case backendVerificationFailed(String)

        var errorDescription: String? {
            switch self {
            case .verificationFailed:
                return "Transaction verification failed"
            case .noProducts:
                return "No products available"
            case .purchaseFailed:
                return "Purchase failed"
            case .backendVerificationFailed(let message):
                return "Backend verification failed: \(message)"
            }
        }
    }
}
