import Foundation
import StoreKit
import Combine

@MainActor
class IAPService: ObservableObject {
    // MARK: - Published Properties

    @Published private(set) var isPremium = false
    @Published private(set) var products: [Product] = []
    @Published private(set) var purchaseState: PurchaseState = .idle
    @Published private(set) var isFamilyShared = false
#if DEBUG
    @Published var debugOverrideEnabled = false
#endif

    // MARK: - Constants

    /// Lifetime unlock (non-consumable). Existing product — keep the id stable.
    static let premiumProductID = "com.portfoliojournal.premium"
    /// Annual auto-renewable subscription with intro free trial. Acts as the primary
    /// offer; lifetime becomes the "best value" anchor. Must be created in App Store
    /// Connect with this exact id — until then the paywall gracefully shows lifetime only.
    static let annualProductID = "com.portfoliojournal.premium.annual"
    static let allProductIDs: Set<String> = [premiumProductID, annualProductID]
    static let premiumPrice = "€4.69"

    // MARK: - Private Properties

    private var updateListenerTask: Task<Void, Error>?
    private var cancellables = Set<AnyCancellable>()
    private let sharedDefaults = UserDefaults(suiteName: AppConstants.appGroupIdentifier)

    // MARK: - Purchase State

    enum PurchaseState: Equatable {
        case idle
        case purchasing
        case purchased
        case failed(String)
        case restored
    }

    // MARK: - Initialization

    init() {
#if DEBUG
        debugOverrideEnabled = UserDefaults.standard.bool(forKey: "debugPremiumOverride")
#endif
        updateListenerTask = listenForTransactions()

        Task {
            await loadProducts()
            await updatePremiumStatus()
        }
    }

#if DEBUG
    func setPremiumForTesting(_ value: Bool, familyShared: Bool = false) {
        isPremium = value
        isFamilyShared = familyShared
    }
#endif

    deinit {
        updateListenerTask?.cancel()
    }

    // MARK: - Load Products

    func loadProducts() async {
        do {
            products = try await Product.products(for: Self.allProductIDs)
            print("Loaded \(products.count) products")
        } catch {
            print("Failed to load products: \(error)")
        }
    }

    // MARK: - Purchase

    /// Purchases the lifetime unlock (backwards-compatible entry point).
    func purchase() async throws {
        guard let product = premiumProduct ?? products.first else {
            throw IAPError.productNotFound
        }
        try await purchase(product)
    }

    /// Purchases a specific product (annual subscription or lifetime unlock).
    func purchase(_ product: Product) async throws {

        purchaseState = .purchasing

        do {
            let result = try await product.purchase()

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

                // Check if family shared
                isFamilyShared = transaction.ownershipType == .familyShared

                await transaction.finish()
                await updatePremiumStatus()

                purchaseState = .purchased

                // Track analytics
                FirebaseService.shared.logPurchaseSuccess(
                    productId: product.id,
                    price: product.price,
                    isFamilyShared: isFamilyShared
                )

            case .userCancelled:
                purchaseState = .idle

            case .pending:
                purchaseState = .idle

            @unknown default:
                purchaseState = .idle
            }
        } catch {
            purchaseState = .failed(error.localizedDescription)
            FirebaseService.shared.logPurchaseFailure(
                productId: product.id,
                error: error.localizedDescription
            )
            throw error
        }
    }

    // MARK: - Restore Purchases

    func restorePurchases() async {
        purchaseState = .purchasing

        do {
            try await AppStore.sync()
            await updatePremiumStatus()

            if isPremium {
                purchaseState = .restored
            } else {
                purchaseState = .failed("No purchases to restore")
            }
        } catch {
            purchaseState = .failed(error.localizedDescription)
        }
    }

    // MARK: - TestFlight Detection

    /// TestFlight builds use a "sandboxReceipt" instead of the production "receipt".
    private var isRunningOnTestFlight: Bool {
        Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
    }

    // MARK: - Update Premium Status

    func updatePremiumStatus() async {
        var isEntitled = false
        var familyShared = false

#if DEBUG
        if debugOverrideEnabled {
            isPremium = true
            isFamilyShared = false
            return
        }
#endif

        // TestFlight builds always get Premium so testers can evaluate all features
        if isRunningOnTestFlight {
            isPremium = true
            isFamilyShared = false
            sharedDefaults?.set(true, forKey: "premiumUnlocked")
            return
        }

        var entitledProductID = Self.premiumProductID
        for await result in StoreKit.Transaction.currentEntitlements {
            if case .verified(let transaction) = result {
                // Lifetime unlock OR an active annual subscription both grant premium.
                if Self.allProductIDs.contains(transaction.productID) {
                    isEntitled = true
                    entitledProductID = transaction.productID
                    familyShared = transaction.ownershipType == .familyShared
                    break
                }
            }
        }

        isPremium = isEntitled
        isFamilyShared = familyShared
        sharedDefaults?.set(isEntitled, forKey: "premiumUnlocked")

        // Update Core Data
        let context = CoreDataStack.shared.viewContext
        PremiumStatus.updateStatus(
            isPremium: isEntitled,
            productIdentifier: entitledProductID,
            transactionId: nil,
            isFamilyShared: familyShared,
            in: context
        )
    }

#if DEBUG
    func setDebugPremiumOverride(_ enabled: Bool) {
        debugOverrideEnabled = enabled
        UserDefaults.standard.set(enabled, forKey: "debugPremiumOverride")
        if enabled {
            isPremium = true
            isFamilyShared = false
            sharedDefaults?.set(true, forKey: "premiumUnlocked")
        } else {
            Task { await updatePremiumStatus() }
        }
    }
#endif

    // MARK: - Transaction Listener

    private func listenForTransactions() -> Task<Void, Error> {
        return Task.detached { [weak self] in
            for await result in StoreKit.Transaction.updates {
                if case .verified(let transaction) = result {
                    await transaction.finish()
                    await self?.updatePremiumStatus()
                }
            }
        }
    }

    // MARK: - Verification

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

    // MARK: - Product Info

    var premiumProduct: Product? {
        products.first { $0.id == Self.premiumProductID }
    }

    /// Annual subscription, nil until the product exists in App Store Connect.
    var annualProduct: Product? {
        products.first { $0.id == Self.annualProductID }
    }

    var formattedPrice: String {
        premiumProduct?.displayPrice ?? Self.premiumPrice
    }

    var formattedAnnualPrice: String? {
        annualProduct?.displayPrice
    }

    /// Localized description of the annual intro offer ("7 days free"), if configured.
    var annualTrialDescription: String? {
        guard let intro = annualProduct?.subscription?.introductoryOffer,
              intro.paymentMode == .freeTrial else { return nil }
        let period = intro.period
        let unit: String
        switch period.unit {
        case .day: unit = String(localized: "paywall_trial_days")
        case .week: unit = String(localized: "paywall_trial_weeks")
        case .month: unit = String(localized: "paywall_trial_months")
        case .year: unit = String(localized: "paywall_trial_years")
        @unknown default: unit = ""
        }
        return String(format: String(localized: "paywall_trial_format"), period.value, unit)
    }
}

// MARK: - IAP Error

enum IAPError: LocalizedError {
    case productNotFound
    case verificationFailed(String)
    case purchaseFailed(String)

    var errorDescription: String? {
        switch self {
        case .productNotFound:
            return "Product not found. Please try again later."
        case .verificationFailed(let message):
            return "Verification failed: \(message)"
        case .purchaseFailed(let message):
            return "Purchase failed: \(message)"
        }
    }
}

// MARK: - Premium Features

extension IAPService {
    static let premiumFeatures: [(icon: String, title: String, description: String)] = [
        ("person.2", "Multiple Accounts", "Separate portfolios for business or family"),
        ("infinity", "Unlimited Sources", "Track as many investments as you want"),
        ("clock.arrow.circlepath", "Full History", "Access your complete investment history"),
        ("chart.bar.xaxis", "Advanced Charts", "5 types of detailed analytics charts"),
        ("wand.and.stars", "Predictions", "AI-powered 12-month forecasts"),
        ("square.and.arrow.up", "Export Data", "Export to CSV and JSON formats"),
        ("xmark.circle", "No Ads", "Ad-free experience forever"),
        ("person.2", "Family Sharing", "Share with up to 5 family members")
    ]

    /// Condensed benefits shown on the paywall (outcome-focused). Multiple Accounts and
    /// Family Sharing are key differentiators vs competitors — keep them visible here.
    static var paywallBenefits: [(icon: String, title: String, subtitle: String)] {[
        ("clock.arrow.circlepath",
         String(localized: "paywall_benefit_history_title"),
         String(localized: "paywall_benefit_history_subtitle")),
        ("chart.bar.xaxis",
         String(localized: "paywall_benefit_charts_title"),
         String(localized: "paywall_benefit_charts_subtitle")),
        ("wand.and.stars",
         String(localized: "paywall_benefit_forecasts_title"),
         String(localized: "paywall_benefit_forecasts_subtitle")),
        ("person.2",
         String(localized: "paywall_benefit_accounts_title"),
         String(localized: "paywall_benefit_accounts_subtitle")),
        ("person.3",
         String(localized: "paywall_benefit_family_title"),
         String(localized: "paywall_benefit_family_subtitle")),
        ("xmark.circle",
         String(localized: "paywall_benefit_noads_title"),
         String(localized: "paywall_benefit_noads_subtitle"))
    ]}
}
