import AppKit
import CodexBarCore
import Testing
@testable import CodexBar

@Suite(.serialized)
@MainActor
struct StatusItemExtraUsageMetricTests {
    @Test
    func `menu bar extra usage preference uses cursor on demand budget`() {
        let (store, controller) = self.makeCursorController(suiteName: "StatusItemExtraUsageMetricTests-budget")
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 20, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            tertiary: RateWindow(usedPercent: 72, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            providerCost: ProviderCostSnapshot(
                used: 15,
                limit: 100,
                currencyCode: "USD",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let window = controller.menuBarMetricWindow(for: .cursor, snapshot: snapshot)

        #expect(window?.usedPercent == 15)
    }

    @Test
    func `menu bar extra usage preference falls back to automatic when cursor on demand budget is missing`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-missing-budget",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 72, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            tertiary: nil,
            providerCost: nil,
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let window = controller.menuBarMetricWindow(for: .cursor, snapshot: snapshot)

        #expect(window?.usedPercent == 72)
    }

    @Test
    func `menu bar extra usage preference honors percent used display for cursor`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-cursor-spend-text",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 20, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            tertiary: RateWindow(usedPercent: 72, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            providerCost: ProviderCostSnapshot(
                used: 12.34,
                limit: 100,
                currencyCode: "USD",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "12%")
    }

    @Test
    func `menu bar extra usage preference honors percent remaining display for cursor`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-cursor-remaining-text",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        controller.settings.usageBarsShowUsed = false
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 20, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            tertiary: RateWindow(usedPercent: 72, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            providerCost: ProviderCostSnapshot(
                used: 12.34,
                limit: 100,
                currencyCode: "USD",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "88%")
    }

    @Test
    func `menu bar extra usage preference keeps cursor currency fallback in pace mode`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-cursor-pace-spend-text",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        controller.settings.menuBarDisplayMode = .pace
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 42, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            providerCost: ProviderCostSnapshot(
                used: 12.34,
                limit: 100,
                currencyCode: "USD",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "$12.34")
    }

    @Test
    func `menu bar extra usage preference uses percent in combined mode`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-cursor-combined-text",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        controller.settings.menuBarDisplayMode = .both
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            providerCost: ProviderCostSnapshot(
                used: 56,
                limit: 100,
                currencyCode: "USD",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "56%")
    }

    @Test
    func `menu bar extra usage preference preserves claude currency display`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-claude-spend-text",
            provider: .claude)
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 42, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            providerCost: ProviderCostSnapshot(
                used: 88.8,
                limit: 200,
                currencyCode: "USD",
                period: "Monthly",
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .claude)
        store._setErrorForTesting(nil, provider: .claude)

        let displayText = controller.menuBarDisplayText(for: .claude, snapshot: snapshot)

        #expect(displayText == "$88.80")
    }

    @Test
    func `menu bar extra usage preference falls back to existing percent text when provider cost is unavailable`() {
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-fallback-percent",
            provider: .cursor)
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 72, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            tertiary: nil,
            providerCost: nil,
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "72%")
    }

    @Test
    func `reset time mode uses extra usage reset instead of spend`() {
        let resetsAt = Date().addingTimeInterval(2 * 24 * 3600)
        let (store, controller) = self.makeController(
            suiteName: "StatusItemExtraUsageMetricTests-reset-time",
            provider: .cursor,
            displayMode: .resetTime,
            resetTimesShowAbsolute: true)
        defer { controller.releaseStatusItemsForTesting() }
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            tertiary: nil,
            providerCost: ProviderCostSnapshot(
                used: 12.34,
                limit: 100,
                currencyCode: "USD",
                period: "Monthly",
                resetsAt: resetsAt,
                updatedAt: Date()),
            updatedAt: Date())

        store._setSnapshotForTesting(snapshot, provider: .cursor)
        store._setErrorForTesting(nil, provider: .cursor)

        let displayText = controller.menuBarDisplayText(for: .cursor, snapshot: snapshot)

        #expect(displayText == "↻ \(UsageFormatter.resetDescription(from: resetsAt))")
    }

    private func makeCursorController(suiteName: String) -> (UsageStore, StatusItemController) {
        self.makeController(suiteName: suiteName, provider: .cursor)
    }

    private func makeController(
        suiteName: String,
        provider: UsageProvider,
        displayMode: MenuBarDisplayMode = .percent,
        resetTimesShowAbsolute: Bool = false) -> (UsageStore, StatusItemController)
    {
        let settings = testSettingsStore(suiteName: suiteName)
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        settings.selectedMenuProvider = provider.instanceID
        settings.menuBarDisplayMode = displayMode
        settings.resetTimesShowAbsolute = resetTimesShowAbsolute
        settings.usageBarsShowUsed = true
        settings.setMenuBarMetricPreference(.extraUsage, for: provider)

        let registry = ProviderRegistry.shared
        if let metadata = registry.metadata[provider] {
            settings.setProviderEnabled(provider: provider, metadata: metadata, enabled: true)
        }

        let fetcher = UsageFetcher()
        let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: fetcher.loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: testStatusBar())
        return (store, controller)
    }
}
