//
//  SubscriptionGatingTests.swift
//  honeyDueTests
//
//  Unit tests for SubscriptionCacheWrapper feature gating logic:
//  currentTier, shouldShowUpgradePrompt, canShareResidence, canShareContractor.
//
//  Uses the shared singleton with serialized tests to avoid race conditions.
//

import Testing
import Foundation
@testable import honeyDue
import ComposeApp

// MARK: - Helpers

/// Build a SubscriptionStatus with sensible defaults for testing.
private func makeSubscription(
    expiresAt: String? = nil,
    limitationsEnabled: Bool = false,
    limits: [String: TierLimits] = [:]
) -> SubscriptionStatus {
    SubscriptionStatus(
        tier: "free",
        isActive: false,
        subscribedAt: nil,
        expiresAt: expiresAt,
        autoRenew: true,
        usage: UsageStats(propertiesCount: 0, tasksCount: 0, contractorsCount: 0, documentsCount: 0),
        limits: limits,
        limitationsEnabled: limitationsEnabled,
        trialStart: nil,
        trialEnd: nil,
        trialActive: false,
        subscriptionSource: nil
    )
}

private let freeLimits = TierLimits(
    properties: KotlinInt(int: 1),
    tasks: KotlinInt(int: 10),
    contractors: KotlinInt(int: 5),
    documents: KotlinInt(int: 5)
)

private let proLimits = TierLimits(
    properties: nil,
    tasks: nil,
    contractors: nil,
    documents: nil
)

// MARK: - Serialized Suite (SubscriptionCacheWrapper is a @MainActor shared singleton)

@MainActor
@Suite(.serialized)
struct SubscriptionGatingTests {

    private let cache = SubscriptionCacheWrapper.shared

    // MARK: - currentTier Tests

    @Test func noSubscriptionTierIsFree() {
        cache.currentSubscription = nil
        #expect(cache.currentTier == "free")
    }

    @Test func subscriptionWithExpiresAtTierIsPro() {
        cache.currentSubscription = makeSubscription(expiresAt: "2030-01-01T00:00:00Z")
        #expect(cache.currentTier == "pro")
    }

    @Test func subscriptionWithEmptyExpiresAtTierIsFree() {
        cache.currentSubscription = makeSubscription(expiresAt: "")
        #expect(cache.currentTier == "free")
    }

    @Test func subscriptionWithNilExpiresAtTierIsFree() {
        cache.currentSubscription = makeSubscription(expiresAt: nil)
        #expect(cache.currentTier == "free")
    }

    // MARK: - shouldShowUpgradePrompt Tests

    @Test func nilSubscriptionNeverBlocks() {
        cache.currentSubscription = nil
        #expect(cache.shouldShowUpgradePrompt(currentCount: 100, limitKey: "properties") == false)
    }

    @Test func limitationsDisabledNeverBlocks() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: false,
            limits: ["free": freeLimits]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 100, limitKey: "properties") == false)
    }

    @Test func proTierNeverBlocks() {
        cache.currentSubscription = makeSubscription(
            expiresAt: "2030-01-01T00:00:00Z",
            limitationsEnabled: true,
            limits: ["pro": proLimits]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 100, limitKey: "properties") == false)
    }

    @Test func freeTierUnderLimitAllowed() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 0, limitKey: "properties") == false)
    }

    @Test func freeTierAtLimitBlocked() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        // freeLimits.properties = 1, so count of 1 should block
        #expect(cache.shouldShowUpgradePrompt(currentCount: 1, limitKey: "properties") == true)
    }

    @Test func freeTierOverLimitBlocked() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 5, limitKey: "properties") == true)
    }

    @Test func tasksLimitEnforced() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        // freeLimits.tasks = 10
        #expect(cache.shouldShowUpgradePrompt(currentCount: 9, limitKey: "tasks") == false)
        #expect(cache.shouldShowUpgradePrompt(currentCount: 10, limitKey: "tasks") == true)
    }

    @Test func contractorsLimitEnforced() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        // freeLimits.contractors = 5
        #expect(cache.shouldShowUpgradePrompt(currentCount: 4, limitKey: "contractors") == false)
        #expect(cache.shouldShowUpgradePrompt(currentCount: 5, limitKey: "contractors") == true)
    }

    @Test func documentsLimitEnforced() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        // freeLimits.documents = 5
        #expect(cache.shouldShowUpgradePrompt(currentCount: 4, limitKey: "documents") == false)
        #expect(cache.shouldShowUpgradePrompt(currentCount: 5, limitKey: "documents") == true)
    }

    @Test func nilLimitMeansUnlimited() {
        let unlimitedTasks = TierLimits(
            properties: KotlinInt(int: 1),
            tasks: nil,
            contractors: nil,
            documents: nil
        )
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": unlimitedTasks]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 10000, limitKey: "tasks") == false)
    }

    @Test func unknownLimitKeyReturnsFalse() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: ["free": freeLimits]
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 100, limitKey: "unknown") == false)
    }

    @Test func noLimitsForTierReturnsFalse() {
        cache.currentSubscription = makeSubscription(
            limitationsEnabled: true,
            limits: [:]  // no "free" key
        )
        #expect(cache.shouldShowUpgradePrompt(currentCount: 100, limitKey: "properties") == false)
    }

    // MARK: - Deprecated shouldShowUpgradePrompt (computed property)

    @Test func deprecatedPromptFreeWithLimitations() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: true)
        #expect(cache.shouldShowUpgradePrompt == true)
    }

    @Test func deprecatedPromptFreeWithoutLimitations() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: false)
        #expect(cache.shouldShowUpgradePrompt == false)
    }

    @Test func deprecatedPromptNilSubscription() {
        cache.currentSubscription = nil
        #expect(cache.shouldShowUpgradePrompt == false)
    }

    // MARK: - canShareResidence Tests

    @Test func canShareResidenceWhenNoSubscription() {
        cache.currentSubscription = nil
        #expect(cache.canShareResidence() == true)
    }

    @Test func canShareResidenceWhenLimitationsDisabled() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: false)
        #expect(cache.canShareResidence() == true)
    }

    @Test func cannotShareResidenceWhenFreeWithLimitations() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: true)
        #expect(cache.canShareResidence() == false)
    }

    @Test func canShareResidenceWhenProWithLimitations() {
        cache.currentSubscription = makeSubscription(
            expiresAt: "2030-01-01T00:00:00Z",
            limitationsEnabled: true
        )
        #expect(cache.canShareResidence() == true)
    }

    // MARK: - canShareContractor Tests

    @Test func canShareContractorWhenNoSubscription() {
        cache.currentSubscription = nil
        #expect(cache.canShareContractor() == true)
    }

    @Test func canShareContractorWhenLimitationsDisabled() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: false)
        #expect(cache.canShareContractor() == true)
    }

    @Test func cannotShareContractorWhenFreeWithLimitations() {
        cache.currentSubscription = makeSubscription(limitationsEnabled: true)
        #expect(cache.canShareContractor() == false)
    }

    @Test func canShareContractorWhenProWithLimitations() {
        cache.currentSubscription = makeSubscription(
            expiresAt: "2030-01-01T00:00:00Z",
            limitationsEnabled: true
        )
        #expect(cache.canShareContractor() == true)
    }
}
