import SwiftUI
import Combine
import ComposeApp

/// Swift wrapper that reads subscription state from Kotlin DataManager (single source of truth).
///
/// DataManager is the authoritative subscription state holder. This wrapper
/// observes DataManager's StateFlows (via targeted Combine observation of
/// DataManagerObservable's subscription-related @Published properties)
/// and publishes changes to SwiftUI views via @Published properties.
@MainActor
class SubscriptionCacheWrapper: ObservableObject {
    static let shared = SubscriptionCacheWrapper()

    @Published var currentSubscription: SubscriptionStatus?
    @Published var upgradeTriggers: [String: UpgradeTriggerData] = [:]
    @Published var featureBenefits: [FeatureBenefit] = []
    @Published var promotions: [Promotion] = []

    private var cancellables = Set<AnyCancellable>()

    /// Current tier derived from backend subscription status, with StoreKit fallback.
    /// Mirrors the logic in Kotlin SubscriptionHelper.currentTier.
    var currentTier: String {
        // Active trial grants pro access.
        if let subscription = currentSubscription, subscription.trialActive {
            return "pro"
        }

        // Prefer backend subscription state when available.
        // `expiresAt` is only expected for active paid plans.
        if let subscription = currentSubscription,
           let expiresAt = subscription.expiresAt,
           !expiresAt.isEmpty {
            // Parse the date and check if subscription is still active
            let formatter = ISO8601DateFormatter()
            formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
            if let expiryDate = formatter.date(from: expiresAt) ?? ISO8601DateFormatter().date(from: expiresAt) {
                if expiryDate > Date() {
                    return "pro"
                }
                // Expired — fall through to StoreKit check
            } else {
                // Can't parse date but backend says there's a subscription
                return "pro"
            }
        }

        // Fallback to local StoreKit entitlements.
        return StoreKitManager.shared.purchasedProductIDs.isEmpty ? "free" : "pro"
    }

    /// Check if user should be blocked from adding an item based on LIVE count
    /// - Parameters:
    ///   - currentCount: The actual current count from the data (e.g., viewModel.residences.count)
    ///   - limitKey: The key to check ("properties", "tasks", "contractors", or "documents")
    /// - Returns: true if should show upgrade prompt (blocked), false if allowed
    func shouldShowUpgradePrompt(currentCount: Int, limitKey: String) -> Bool {
        // Never gate features during UI tests
        if UITestRuntime.isEnabled { return false }

        // If limitations are disabled globally, never block
        guard let subscription = currentSubscription, subscription.limitationsEnabled else {
            return false
        }

        // Pro tier never gets blocked
        if currentTier == "pro" {
            return false
        }

        // Get the appropriate limits for the current tier
        guard let tierLimits = subscription.limits[currentTier] else {
            print("No limits found for tier: \(currentTier)")
            return false
        }

        // Get the specific limit for this resource type
        let limit: Int?
        switch limitKey {
        case "properties":
            limit = tierLimits.properties.map { Int(truncating: $0) }
        case "tasks":
            limit = tierLimits.tasks.map { Int(truncating: $0) }
        case "contractors":
            limit = tierLimits.contractors.map { Int(truncating: $0) }
        case "documents":
            limit = tierLimits.documents.map { Int(truncating: $0) }
        default:
            print("Unknown limit key: \(limitKey)")
            return false
        }

        // nil limit means unlimited
        guard let actualLimit = limit else {
            return false
        }

        // Block if current count >= actualLimit
        return currentCount >= Int(actualLimit)
    }

    /// Deprecated: Use shouldShowUpgradePrompt(currentCount:limitKey:) instead
    var shouldShowUpgradePrompt: Bool {
        if UITestRuntime.isEnabled { return false }
        return currentTier == "free" && (currentSubscription?.limitationsEnabled ?? false)
    }

    /// Check if user can share residences (Pro feature)
    /// - Returns: true if allowed, false if should show upgrade prompt
    func canShareResidence() -> Bool {
        if UITestRuntime.isEnabled { return true }
        // If limitations are disabled globally, allow
        guard let subscription = currentSubscription, subscription.limitationsEnabled else {
            return true
        }
        // Pro tier can share
        return currentTier == "pro"
    }

    /// Check if user can share contractors (Pro feature)
    /// - Returns: true if allowed, false if should show upgrade prompt
    func canShareContractor() -> Bool {
        if UITestRuntime.isEnabled { return true }
        // If limitations are disabled globally, allow
        guard let subscription = currentSubscription, subscription.limitationsEnabled else {
            return true
        }
        // Pro tier can share
        return currentTier == "pro"
    }

    private init() {
        // Observe only subscription-related @Published properties from DataManagerObservable
        // instead of the broad objectWillChange (which fires on ALL 25+ property changes).

        DataManagerObservable.shared.$subscription
            .sink { [weak self] subscription in
                guard let self else { return }
                if self.currentSubscription != subscription {
                    self.currentSubscription = subscription
                    if let subscription {
                        self.syncWidgetSubscriptionStatus(subscription: subscription)
                    }
                }
            }
            .store(in: &cancellables)

        DataManagerObservable.shared.$upgradeTriggers
            .sink { [weak self] triggers in
                self?.upgradeTriggers = triggers
            }
            .store(in: &cancellables)

        DataManagerObservable.shared.$featureBenefits
            .sink { [weak self] benefits in
                self?.featureBenefits = benefits
            }
            .store(in: &cancellables)

        DataManagerObservable.shared.$promotions
            .sink { [weak self] promos in
                self?.promotions = promos
            }
            .store(in: &cancellables)
    }

    func refreshFromCache() {
        // Trigger a re-read from DataManager; the Combine subscriptions will
        // propagate changes automatically when DataManagerObservable updates.
        let subscription = ComposeApp.DataManager.shared.subscription.value as? SubscriptionStatus
        if self.currentSubscription != subscription {
            self.currentSubscription = subscription
            if let subscription {
                syncWidgetSubscriptionStatus(subscription: subscription)
            }
        }
    }

    func updateSubscription(_ subscription: SubscriptionStatus) {
        // Write to DataManager (single source of truth)
        ComposeApp.DataManager.shared.setSubscription(subscription: subscription)
        // Update local state directly (@MainActor guarantees main thread)
        self.currentSubscription = subscription
        syncWidgetSubscriptionStatus(subscription: subscription)
    }

    /// Sync subscription status with widget extension
    private func syncWidgetSubscriptionStatus(subscription: SubscriptionStatus) {
        let limitationsEnabled = subscription.limitationsEnabled
        let isPremium = currentTier == "pro"
        WidgetDataManager.shared.saveSubscriptionStatus(
            limitationsEnabled: limitationsEnabled,
            isPremium: isPremium
        )
    }

    func clear() {
        // Clear via DataManager (single source of truth)
        ComposeApp.DataManager.shared.setSubscription(subscription: nil)
        ComposeApp.DataManager.shared.setUpgradeTriggers(triggers: [:])
        ComposeApp.DataManager.shared.setFeatureBenefits(benefits: [])
        ComposeApp.DataManager.shared.setPromotions(promos: [])
        // Update local state directly (@MainActor guarantees main thread)
        self.currentSubscription = nil
        self.upgradeTriggers = [:]
        self.featureBenefits = []
        self.promotions = []
    }
}
