import Testing
import Foundation
@testable import nahbar

// MARK: - SubscriptionTier Tests

@Suite("SubscriptionTier – Enum")
struct SubscriptionTierTests {

    @Test("Genau 2 Tiers vorhanden")
    func allCasesCount() {
        #expect(SubscriptionTier.allCases.count == 2)
    }

    @Test("Pro productID ist 'profeatures'")
    func proProductID() {
        #expect(SubscriptionTier.pro.productID == "profeatures")
    }

    @Test("Max productID ist 'maxfeatures'")
    func maxProductID() {
        #expect(SubscriptionTier.max.productID == "maxfeatures")
    }

    @Test("Pro displayName ist 'Pro'")
    func proDisplayName() {
        #expect(SubscriptionTier.pro.displayName == "Pro")
    }

    @Test("Max displayName ist 'Max'")
    func maxDisplayName() {
        #expect(SubscriptionTier.max.displayName == "Max")
    }

    @Test("productIDs sind einzigartig")
    func productIDsAreUnique() {
        let ids = SubscriptionTier.allCases.map { $0.productID }
        #expect(Set(ids).count == SubscriptionTier.allCases.count)
    }

    @Test("displayNames sind einzigartig")
    func displayNamesAreUnique() {
        let names = SubscriptionTier.allCases.map { $0.displayName }
        #expect(Set(names).count == SubscriptionTier.allCases.count)
    }

    @Test("productIDs sind nicht leer")
    func productIDsNotEmpty() {
        for tier in SubscriptionTier.allCases {
            #expect(!tier.productID.isEmpty)
        }
    }
}

// MARK: - AI Free Query Counter Tests

// Tests laufen serialisiert, da alle auf UserDefaults.standard mit gleichem Key schreiben
@Suite("AIAnalysisService – Gratis-Abfragen", .serialized)
struct AIFreeQueryTests {

    init() {
        AIAnalysisService.shared.freeQueriesUsed = 0
    }

    @Test("Limit ist genau 3")
    func limitIsThree() {
        #expect(AIAnalysisService.freeQueryLimit == 3)
    }

    @Test("Initial: Abfragen verfügbar, remaining = 3")
    func initialState() {
        AIAnalysisService.shared.freeQueriesUsed = 0
        #expect(AIAnalysisService.shared.hasFreeQueriesLeft == true)
        #expect(AIAnalysisService.shared.freeQueriesRemaining == 3)
    }

    @Test("consumeFreeQuery erhöht Zähler um 1")
    func consumeIncrementsCounter() {
        AIAnalysisService.shared.freeQueriesUsed = 0
        AIAnalysisService.shared.consumeFreeQuery()
        #expect(AIAnalysisService.shared.freeQueriesUsed == 1)
        #expect(AIAnalysisService.shared.freeQueriesRemaining == 2)
    }

    @Test("Nach 3 Verbrauchungen: hasFreeQueriesLeft == false")
    func afterThreeConsumed() {
        AIAnalysisService.shared.freeQueriesUsed = 0
        AIAnalysisService.shared.consumeFreeQuery()
        AIAnalysisService.shared.consumeFreeQuery()
        AIAnalysisService.shared.consumeFreeQuery()
        #expect(AIAnalysisService.shared.hasFreeQueriesLeft == false)
        #expect(AIAnalysisService.shared.freeQueriesRemaining == 0)
    }

    @Test("Zähler über Limit: remaining bleibt 0, nicht negativ")
    func remainingNotNegative() {
        AIAnalysisService.shared.freeQueriesUsed = 10
        #expect(AIAnalysisService.shared.freeQueriesRemaining == 0)
        #expect(AIAnalysisService.shared.hasFreeQueriesLeft == false)
    }

    @Test("Zähler = limit - 1: noch genau 1 Abfrage verfügbar")
    func oneQueryLeft() {
        AIAnalysisService.shared.freeQueriesUsed = AIAnalysisService.freeQueryLimit - 1
        #expect(AIAnalysisService.shared.hasFreeQueriesLeft == true)
        #expect(AIAnalysisService.shared.freeQueriesRemaining == 1)
    }

    @Test("Zähler = limit: keine Abfragen mehr verfügbar")
    func atLimit() {
        AIAnalysisService.shared.freeQueriesUsed = AIAnalysisService.freeQueryLimit
        #expect(AIAnalysisService.shared.hasFreeQueriesLeft == false)
    }

    @Test("freeQueriesUsed + freeQueriesRemaining = limit (solange unter limit)")
    func usedPlusRemainingEqualsLimit() {
        for used in 0...AIAnalysisService.freeQueryLimit {
            AIAnalysisService.shared.freeQueriesUsed = used
            let remaining = AIAnalysisService.shared.freeQueriesRemaining
            #expect(used + remaining == AIAnalysisService.freeQueryLimit)
        }
    }
}

// MARK: - AppGroup Pro-Status Tests

// Tests laufen serialisiert, da alle dieselbe UserDefaults-Suite nutzen
@Suite("AppGroup – Pro-Status", .serialized)
struct AppGroupProStatusTests {

    private let testDefaults = UserDefaults(suiteName: "nahbar.test.proStatus")!

    init() {
        testDefaults.removeObject(forKey: "isPro")
        testDefaults.synchronize()
    }

    @Test("Pro-Status initial false wenn nicht gesetzt")
    func proStatusInitiallyFalse() {
        testDefaults.removeObject(forKey: "isPro")
        #expect(testDefaults.bool(forKey: "isPro") == false)
    }

    @Test("Pro-Status round-trip: true")
    func proStatusRoundTripTrue() {
        testDefaults.set(true, forKey: "isPro")
        #expect(testDefaults.bool(forKey: "isPro") == true)
    }

    @Test("Pro-Status round-trip: false")
    func proStatusRoundTripFalse() {
        testDefaults.set(true, forKey: "isPro")
        testDefaults.set(false, forKey: "isPro")
        #expect(testDefaults.bool(forKey: "isPro") == false)
    }

    @Test("Pro-Status nach removeObject ist false")
    func proStatusAfterRemoveIsFalse() {
        testDefaults.set(true, forKey: "isPro")
        testDefaults.removeObject(forKey: "isPro")
        #expect(testDefaults.bool(forKey: "isPro") == false)
    }
}

// MARK: - Paywall-Targeting Tests

/// Dokumentiert die Logik aus SettingsView:
///   PaywallView(targeting: store.isPro ? .max : .pro)
/// Stellt sicher, dass der Einstiegs-Tab beim Öffnen des Paywalls korrekt ist.
@Suite("Paywall – Ziel-Tier basierend auf isPro")
struct PaywallTargetingTests {

    /// Repliziert die einzeilige Entscheidungslogik aus SettingsView.
    private func target(isPro: Bool) -> SubscriptionTier {
        isPro ? .max : .pro
    }

    @Test("Kein Abo → Paywall öffnet Pro-Tab")
    func noSubscriptionTargetsPro() {
        #expect(target(isPro: false) == .pro)
    }

    @Test("Pro-only → Paywall öffnet Max-Tab (Upgrade-Pfad)")
    func proOnlyTargetsMax() {
        #expect(target(isPro: true) == .max)
    }

    @Test("Ziel-Tiers sind unterschiedlich")
    func targetsAreDistinct() {
        #expect(target(isPro: false) != target(isPro: true))
    }
}
