import CodexBarCore
import Foundation
import Testing
@testable import CodexBar

struct CursorMenuCardModelTests {
    @Test
    func `chosen app session account identity is visible on the card`() throws {
        let now = Date(timeIntervalSince1970: 0)
        let metadata = try #require(ProviderDefaults.metadata[.cursor])
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 25, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            updatedAt: now,
            identity: ProviderIdentitySnapshot(
                providerID: .cursor,
                accountEmail: nil,
                accountOrganization: nil,
                loginMethod: "Cursor Pro",
                accountID: "auth0|app-user"))

        let model = UsageMenuCardView.Model.make(.init(
            provider: .cursor,
            metadata: metadata,
            snapshot: snapshot,
            credits: nil,
            creditsError: nil,
            dashboard: nil,
            dashboardError: nil,
            tokenSnapshot: nil,
            tokenError: nil,
            account: AccountInfo(email: "web@example.com", plan: nil),
            isRefreshing: false,
            lastError: nil,
            usageBarsShowUsed: false,
            resetTimeDisplayStyle: .countdown,
            tokenCostUsageEnabled: false,
            showOptionalCreditsAndExtraUsage: true,
            hidePersonalInfo: false,
            now: now))

        #expect(model.email == "app-user")
    }

    @Test
    func `team pool shows personal spend and changes height fingerprint`() throws {
        let now = Date(timeIntervalSince1970: 0)
        let metadata = try #require(ProviderDefaults.metadata[.cursor])

        #expect(metadata.supportsCredits == false)

        func makeModel(
            personalUsed: Double?,
            showOptionalUsage: Bool = true) -> UsageMenuCardView.Model
        {
            let snapshot = UsageSnapshot(
                primary: nil,
                secondary: nil,
                tertiary: nil,
                providerCost: ProviderCostSnapshot(
                    used: 13111.25,
                    limit: 20000,
                    currencyCode: "USD",
                    period: "Monthly",
                    personalUsed: personalUsed,
                    updatedAt: now),
                updatedAt: now,
                identity: nil)
            return UsageMenuCardView.Model.make(.init(
                provider: .cursor,
                metadata: metadata,
                snapshot: snapshot,
                credits: nil,
                creditsError: nil,
                dashboard: nil,
                dashboardError: nil,
                tokenSnapshot: nil,
                tokenError: nil,
                account: AccountInfo(email: nil, plan: nil),
                isRefreshing: false,
                lastError: nil,
                usageBarsShowUsed: false,
                resetTimeDisplayStyle: .countdown,
                tokenCostUsageEnabled: false,
                showOptionalCreditsAndExtraUsage: showOptionalUsage,
                hidePersonalInfo: false,
                now: now))
        }

        let personal = makeModel(personalUsed: 44.71)
        let absent = makeModel(personalUsed: nil)
        let zero = makeModel(personalUsed: 0)
        let hidden = makeModel(personalUsed: 44.71, showOptionalUsage: false)

        #expect(personal.creditsText == nil)
        #expect(personal.providerCost?.title == "Extra usage")
        #expect(personal.providerCost?.personalSpendLine == "Your spend: $44.71")
        #expect(absent.providerCost?.personalSpendLine == nil)
        #expect(zero.providerCost?.personalSpendLine == nil)
        #expect(hidden.providerCost == nil)
        #expect(personal.heightFingerprint(section: "card") != absent.heightFingerprint(section: "card"))
        #expect(!personal.hasCompatibleTrackedLayout(with: absent))
        #expect(!absent.hasCompatibleTrackedLayout(with: personal))
    }

    @Test
    func `cursor billing cycle metrics show deficit and run out details`() throws {
        let now = Date(timeIntervalSince1970: 0)
        let reset = now.addingTimeInterval(6 * 24 * 3600)
        let cycleMinutes = 30 * 24 * 60
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 90, windowMinutes: cycleMinutes, resetsAt: reset, resetDescription: nil),
            secondary: RateWindow(usedPercent: 90, windowMinutes: cycleMinutes, resetsAt: reset, resetDescription: nil),
            tertiary: RateWindow(usedPercent: 90, windowMinutes: cycleMinutes, resetsAt: reset, resetDescription: nil),
            updatedAt: now,
            identity: nil)
        let metadata = try #require(ProviderDefaults.metadata[.cursor])

        let model = UsageMenuCardView.Model.make(.init(
            provider: .cursor,
            metadata: metadata,
            snapshot: snapshot,
            credits: nil,
            creditsError: nil,
            dashboard: nil,
            dashboardError: nil,
            tokenSnapshot: nil,
            tokenError: nil,
            account: AccountInfo(email: nil, plan: nil),
            isRefreshing: false,
            lastError: nil,
            usageBarsShowUsed: false,
            resetTimeDisplayStyle: .countdown,
            tokenCostUsageEnabled: false,
            showOptionalCreditsAndExtraUsage: true,
            hidePersonalInfo: false,
            now: now))

        #expect(model.metrics.map(\.title) == ["Total", "Cursor", "Third Party"])
        for metric in model.metrics {
            #expect(metric.percentLabel == "10% left")
            #expect(metric.detailLeftText == "10% in deficit")
            #expect(metric.detailRightText == "Runs out in 2d 16h")
            #expect(metric.pacePercent == 20)
            #expect(metric.paceOnTop == false)
        }
    }

    @Test
    func `cursor billing cycle metrics hide pace when quota is depleted`() throws {
        let now = Date(timeIntervalSince1970: 0)
        let reset = now.addingTimeInterval(6 * 24 * 3600)
        let cycleMinutes = 30 * 24 * 60
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 100, windowMinutes: cycleMinutes, resetsAt: reset, resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 100,
                windowMinutes: cycleMinutes,
                resetsAt: reset,
                resetDescription: nil),
            tertiary: RateWindow(usedPercent: 100, windowMinutes: cycleMinutes, resetsAt: reset, resetDescription: nil),
            updatedAt: now,
            identity: nil)
        let metadata = try #require(ProviderDefaults.metadata[.cursor])

        let model = UsageMenuCardView.Model.make(.init(
            provider: .cursor,
            metadata: metadata,
            snapshot: snapshot,
            credits: nil,
            creditsError: nil,
            dashboard: nil,
            dashboardError: nil,
            tokenSnapshot: nil,
            tokenError: nil,
            account: AccountInfo(email: nil, plan: nil),
            isRefreshing: false,
            lastError: nil,
            usageBarsShowUsed: false,
            resetTimeDisplayStyle: .countdown,
            tokenCostUsageEnabled: false,
            showOptionalCreditsAndExtraUsage: true,
            hidePersonalInfo: false,
            now: now))

        #expect(model.metrics.map(\.title) == ["Total", "Cursor", "Third Party"])
        for metric in model.metrics {
            #expect(metric.percentLabel == "0% left")
            #expect(metric.detailLeftText == nil)
            #expect(metric.detailRightText == nil)
            #expect(metric.pacePercent == nil)
        }
    }

    @Test
    func `legacy request plan shows single requests bar with count`() throws {
        let now = Date(timeIntervalSince1970: 0)
        let reset = now.addingTimeInterval(6 * 24 * 3600)
        let cycleMinutes = 30 * 24 * 60
        // A legacy snapshot, as produced by CursorStatusSnapshot.toUsageSnapshot(): only the request
        // window survives, Auto/API are dropped, and the request count rides along.
        let snapshot = try UsageSnapshot(
            primary: RateWindow(
                usedPercent: 69.4,
                windowMinutes: cycleMinutes,
                resetsAt: reset,
                resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            details: [ProviderDetailSection(rows: [
                ProviderDetailSection.Row(label: "Request quota", value: "347 / 500"),
            ])],
            updatedAt: now,
            identity: nil)
        let metadata = try #require(ProviderDefaults.metadata[.cursor])

        let model = UsageMenuCardView.Model.make(.init(
            provider: .cursor,
            metadata: metadata,
            snapshot: snapshot,
            credits: nil,
            creditsError: nil,
            dashboard: nil,
            dashboardError: nil,
            tokenSnapshot: nil,
            tokenError: nil,
            account: AccountInfo(email: nil, plan: nil),
            isRefreshing: false,
            lastError: nil,
            usageBarsShowUsed: false,
            resetTimeDisplayStyle: .countdown,
            tokenCostUsageEnabled: false,
            showOptionalCreditsAndExtraUsage: true,
            hidePersonalInfo: false,
            now: now))

        #expect(model.metrics.map(\.title) == ["Requests"])
        #expect(model.metrics.first?.detailText == "Request quota: 347 / 500")
    }
}
