import AppKit
import CodexBarCore
import SwiftUI
import Testing
@testable import CodexBar

private final class RefreshShortcutRecorder: StatusItemMenuPersistentActionDelegate {
    var refreshCount = 0
    var refreshMenuIDs: [ObjectIdentifier] = []
    var refreshMenuInteractionGenerations: [Int] = []
    var settingsCount = 0
    var quitCount = 0
    var navigationDirections: [StatusItemMenuProviderNavigationDirection] = []

    func performPersistentRefreshAction(
        in menuID: ObjectIdentifier,
        menuInteractionGeneration: Int)
    {
        self.refreshCount += 1
        self.refreshMenuIDs.append(menuID)
        self.refreshMenuInteractionGenerations.append(menuInteractionGeneration)
    }

    func performPersistentSettingsAction() {
        self.settingsCount += 1
    }

    func performPersistentQuitAction() {
        self.quitCount += 1
    }

    func performProviderNavigation(_ direction: StatusItemMenuProviderNavigationDirection) {
        self.navigationDirections.append(direction)
    }
}

@MainActor
private final class UpdateReadyUpdater: UpdaterProviding {
    var automaticallyChecksForUpdates = false
    var automaticallyDownloadsUpdates = false
    let isAvailable = true
    let unavailableReason: String? = nil
    let updateStatus = UpdateStatus(isUpdateReady: true)

    func checkForUpdates(_: Any?) {}
    func installUpdate() {}
}

@MainActor
private final class ManualRefreshGate {
    private var continuation: CheckedContinuation<Void, Never>?
    private var isOpen = false

    func wait() async {
        if self.isOpen {
            self.isOpen = false
            return
        }
        await withCheckedContinuation { continuation in
            self.continuation = continuation
        }
    }

    func resume() {
        if let continuation = self.continuation {
            continuation.resume()
            self.continuation = nil
        } else {
            self.isOpen = true
        }
    }

    func waitUntilSignaled(timeout: Duration = .seconds(5)) async -> Bool {
        let deadline = ContinuousClock.now + timeout
        while !self.isOpen {
            if ContinuousClock.now >= deadline {
                return false
            }
            try? await Task.sleep(for: .milliseconds(10))
        }
        self.isOpen = false
        return true
    }
}

enum BlockingEnrichmentStage: Sendable {
    case credits
    case dashboard
}

@MainActor
@Suite(.serialized)
struct StatusMenuPersistentRefreshTests {
    private func makeSettings() -> SettingsStore {
        testSettingsStore(suiteName: "StatusMenuPersistentRefreshTests")
    }

    private func makeController(
        settings: SettingsStore,
        updater: UpdaterProviding = DisabledUpdaterController(),
        account: AccountInfo? = nil) -> StatusItemController
    {
        let environment = Self.isolatedEnvironment()
        let fetcher = UsageFetcher(environment: environment)
        let store = UsageStore(
            fetcher: fetcher,
            browserDetection: BrowserDetection(cacheTTL: 0),
            settings: settings,
            startupBehavior: .testing,
            environmentBase: environment)
        if let account {
            store.accountInfoCache[.codex] = UsageStore.AccountInfoCacheEntry(
                account: account,
                configRevision: settings.configRevision,
                expiresAt: .distantFuture)
        }
        return StatusItemController(
            store: store,
            settings: settings,
            account: account ?? AccountInfo(email: nil, plan: nil),
            updater: updater,
            preferencesSelection: PreferencesSelection(),
            statusBar: .system)
    }

    private static func isolatedEnvironment() -> [String: String] {
        let root = FileManager.default.temporaryDirectory
            .appendingPathComponent("codexbar-tests", isDirectory: true)
            .appendingPathComponent(UUID().uuidString, isDirectory: true)
        return [
            "HOME": root.path,
            "CODEX_HOME": root.appendingPathComponent(".codex", isDirectory: true).path,
            "XDG_CONFIG_HOME": root.appendingPathComponent(".config", isDirectory: true).path,
        ]
    }

    private func enableOnly(_ providers: Set<UsageProvider>, settings: SettingsStore) {
        for provider in UsageProvider.allCases {
            guard let metadata = ProviderRegistry.shared.metadata[provider] else { continue }
            settings.setProviderEnabled(provider: provider, metadata: metadata, enabled: providers.contains(provider))
        }
    }

    private static func makeTokenSnapshot() -> CostUsageTokenSnapshot {
        CostUsageTokenSnapshot(
            sessionTokens: 123,
            sessionCostUSD: 0.12,
            last30DaysTokens: 456,
            last30DaysCostUSD: 1.23,
            daily: [],
            updatedAt: Date())
    }

    @Test
    func `refresh row is custom and appears above settings`() throws {
        let previousRendering = StatusItemController.menuCardRenderingEnabled
        StatusItemController.menuCardRenderingEnabled = true
        defer { StatusItemController.menuCardRenderingEnabled = previousRendering }

        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)

        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)

        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        let settingsItem = try #require(menu.items.first { $0.title == "Settings..." })
        let refreshIndex = try #require(menu.items.firstIndex(where: { $0 === refreshItem }))
        let settingsIndex = try #require(menu.items.firstIndex(where: { $0 === settingsItem }))

        #expect(refreshItem.action == nil)
        #expect(refreshItem.target == nil)
        let refreshView = try #require(refreshItem.view)
        #expect(refreshView is any MenuCardHighlighting)
        #expect(refreshView.fittingSize.height > 0)
        #expect(controller.isPersistentRefreshItem(refreshItem))
        #expect(refreshItem.keyEquivalent.isEmpty)
        #expect(refreshItem.keyEquivalentModifierMask.isEmpty)
        #expect(refreshIndex < settingsIndex)
    }

    @Test
    func `persistent refresh installs tracking monitor and handles command R without native shortcut`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)
        controller.menuRefreshEnabledOverrideForTesting = true
        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(controller.isPersistentRefreshItem(refreshItem))
        #expect(controller.providerSwitcherShortcutEventMonitor != nil)
        #expect(controller.providerSwitcherShortcutMenuID == ObjectIdentifier(menu))
        #expect(refreshItem.keyEquivalent.isEmpty)

        let gate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await gate.wait() }
        #expect(try controller.handleMenuTrackingShortcutEvent(self.keyEvent("r", keyCode: 15), menu: menu))
        for _ in 0..<20 where controller.manualRefreshTasks[.provider(.codex)] == nil {
            await Task.yield()
        }

        let task = try #require(controller.manualRefreshTasks[.provider(.codex)])
        #expect(!refreshItem.isEnabled)

        gate.resume()
        await task.value

        #expect(controller.manualRefreshTasks[.provider(.codex)] == nil)
        #expect(refreshItem.isEnabled)
    }

    @Test
    func `only refresh uses a custom row while standard actions stay native`() throws {
        let previousRendering = StatusItemController.menuCardRenderingEnabled
        StatusItemController.menuCardRenderingEnabled = true
        defer { StatusItemController.menuCardRenderingEnabled = previousRendering }

        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings, updater: UpdateReadyUpdater())
        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)

        let updateItem = try #require(menu.items.first { $0.title == "Update ready, restart now?" })
        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(MenuDescriptor.MenuAction.installUpdate.systemImageName == "arrow.down.circle")
        #expect(MenuDescriptor.MenuAction.dashboard.systemImageName == "chart.xyaxis.line")
        #expect(updateItem.image != nil)
        #expect(refreshItem.view is any MenuCardHighlighting)
        #expect(refreshItem.action == nil)
        #expect(controller.isPersistentRefreshItem(refreshItem))
        #expect(refreshItem.keyEquivalent.isEmpty)
        #expect(refreshItem.keyEquivalentModifierMask.isEmpty)

        #expect(updateItem.view == nil)
        #expect(updateItem.action != nil)
        #expect(updateItem.target === controller)

        for (title, key) in [("Settings...", ","), ("About CodexBar", ""), ("Quit", "q")] {
            let item = try #require(menu.items.first { $0.title == title })
            #expect(item.view == nil)
            #expect(item.action != nil)
            #expect(item.target === controller)
            #expect(item.keyEquivalent == key)
            if !key.isEmpty {
                #expect(item.keyEquivalentModifierMask == [.command])
            }
        }
    }

    @Test
    func `persistent refresh row reflects scoped global and manual refresh state`() throws {
        let previousRendering = StatusItemController.menuCardRenderingEnabled
        StatusItemController.menuCardRenderingEnabled = true
        defer { StatusItemController.menuCardRenderingEnabled = previousRendering }

        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)
        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)

        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(controller.isPersistentRefreshItem(refreshItem))
        #expect(controller.persistentRefreshItems.allObjects.contains { $0 === refreshItem })
        #expect(refreshItem.isEnabled)

        controller.store.refreshingProviders.insert(.claude)
        controller.updatePersistentRefreshItemsEnabled()
        #expect(refreshItem.isEnabled)

        controller.store.refreshingProviders.insert(.codex)
        controller.updatePersistentRefreshItemsEnabled()
        #expect(!refreshItem.isEnabled)

        controller.store.refreshingProviders.removeAll()
        controller.store.isRefreshing = true
        controller.updatePersistentRefreshItemsEnabled()
        #expect(!refreshItem.isEnabled)

        controller.store.isRefreshing = false

        // A manual refresh scoped to another provider must not grey out this provider's row.
        controller.manualRefreshTasks[.provider(.claude)] = Task {}
        controller.updatePersistentRefreshItemsEnabled()
        #expect(refreshItem.isEnabled)

        // This provider's own manual refresh does disable its row.
        controller.manualRefreshTasks[.provider(.codex)] = Task {}
        controller.updatePersistentRefreshItemsEnabled()
        #expect(!refreshItem.isEnabled)

        controller.manualRefreshTasks[.provider(.codex)] = nil
        controller.manualRefreshTasks[.provider(.claude)] = nil
        controller.updatePersistentRefreshItemsEnabled()
        #expect(refreshItem.isEnabled)

        // An all-providers refresh greys every row.
        controller.manualRefreshTasks[.global] = Task {}
        controller.updatePersistentRefreshItemsEnabled()
        #expect(!refreshItem.isEnabled)

        controller.manualRefreshTasks[.global] = nil
        controller.updatePersistentRefreshItemsEnabled()
        #expect(refreshItem.isEnabled)

        refreshItem.representedObject = "notRefresh"
        controller.manualRefreshTasks[.global] = Task {}
        controller.updatePersistentRefreshItemsEnabled()
        #expect(refreshItem.isEnabled)
        #expect(!controller.persistentRefreshItems.allObjects.contains { $0 === refreshItem })
        controller.manualRefreshTasks[.global] = nil
    }

    @Test
    func `refresh monitor follows refresh success and failure`() {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let monitor = controller.menuCardRefreshMonitor
        let fallback = MenuCardLiveSubtitle(text: "Fallback", style: .info)

        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)

        controller.store.refreshingProviders.insert(.codex)
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .loading)

        controller.store.refreshingProviders.remove(.codex)
        monitor.beginManualRefresh(frozenModels: [:], provider: nil)
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)
        controller.store.refreshingProviders.insert(.codex)
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .loading)
        monitor.endManualRefresh()
        controller.store.refreshingProviders.remove(.codex)

        let now = Date()
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 10,
                windowMinutes: nil,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let success = monitor.subtitle(for: .codex, fallback: fallback)
        #expect(success.style == .info)
        #expect(success.text == UsageFormatter.updatedString(from: now, now: Date()))

        controller.store.errors[.codex] = "Refresh failed"
        let failure = monitor.subtitle(for: .codex, fallback: fallback)
        #expect(failure.style == .error)
        #expect(failure.text == "Refresh failed")

        monitor.beginManualRefresh(frozenModels: [:], provider: nil)
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .error)
        controller.store.refreshingProviders.insert(.codex)
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .loading)
        controller.store.refreshingProviders.remove(.codex)
    }

    @Test
    func `scoped refresh monitor leaves unrelated providers unchanged`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let monitor = controller.menuCardRefreshMonitor
        let codexModel = try #require(controller.menuCardModel(for: .codex))
        let fallback = MenuCardLiveSubtitle(text: "Claude idle", style: .info)
        let expectedClaude = monitor.subtitle(for: .claude, fallback: fallback)

        monitor.beginManualRefresh(frozenModels: [.codex: codexModel], provider: .codex)
        defer { monitor.endManualRefresh(for: .codex) }

        #expect(monitor.isManualRefreshInFlight(for: .codex))
        #expect(!monitor.isManualRefreshInFlight(for: .claude))
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .loading)
        let actualClaude = monitor.subtitle(for: .claude, fallback: fallback)
        #expect(actualClaude.text == expectedClaude.text)
        #expect(actualClaude.style == expectedClaude.style)
    }

    @Test
    func `refresh monitor updates compatible usage values after manual refresh completes`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let now = Date()
        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 10,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 20,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7200),
                resetDescription: nil),
            updatedAt: now)
        let fallback = try #require(controller.menuCardModel(for: .claude))
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [:], provider: .claude)

        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 65,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 75,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7200),
                resetDescription: nil),
            updatedAt: now.addingTimeInterval(1))

        let inFlight = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)
        #expect(inFlight.metrics.map(\.percent) == fallback.metrics.map(\.percent))

        controller.menuCardRefreshMonitor.endManualRefresh(for: .claude)
        let refreshed = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)
        let expected = try #require(controller.menuCardModel(for: .claude))

        #expect(refreshed.metrics.map(\.percent) == expected.metrics.map(\.percent))
        #expect(refreshed.metrics.map(\.percent) != fallback.metrics.map(\.percent))
    }

    @Test
    func `refresh monitor publishes compatible core and pins it until final reconciliation`() throws {
        let settings = self.makeSettings()
        self.enableOnly([.codex], settings: settings)
        let controller = self.makeController(settings: settings)
        defer { controller.releaseStatusItemsForTesting() }
        let monitor = controller.menuCardRefreshMonitor
        let now = Date(timeIntervalSince1970: 1_700_000_000)
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 10,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .codex))
        monitor.beginManualRefresh(frozenModels: [.codex: frozen], provider: .codex)
        defer { monitor.endManualRefresh(for: .codex) }

        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 40,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now.addingTimeInterval(1))
        let core = try #require(controller.menuCardModel(for: .codex))

        #expect(monitor.publishResolvedModelIfCompatible(for: .codex))
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.model(for: .codex, fallback: frozen).metrics.map(\.percent) == core.metrics.map(\.percent))

        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 40,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 70,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7200),
                resetDescription: nil),
            updatedAt: now.addingTimeInterval(2))
        let enriched = try #require(controller.menuCardModel(for: .codex))
        let visibleBeforeReconciliation = monitor.model(for: .codex, fallback: frozen)
        let visibleAfterReconciliation = monitor.model(for: .codex, fallback: enriched)

        #expect(visibleBeforeReconciliation.metrics.map(\.percent) == core.metrics.map(\.percent))
        #expect(visibleAfterReconciliation.metrics.map(\.percent) == enriched.metrics.map(\.percent))
        if ProcessInfo.processInfo.environment["CODEXBAR_REFRESH_PROBE"] == "1" {
            print(
                "CODEXBAR_REFRESH_PROBE compatible-layout-shift refreshing=false pinned=" +
                    "\(visibleBeforeReconciliation.metrics.first?.percentLabel ?? "none") " +
                    "reconciledRows=\(visibleAfterReconciliation.metrics.count)")
        }
    }

    @Test
    func `refresh monitor keeps incompatible core frozen until reconciliation`() throws {
        let settings = self.makeSettings()
        self.enableOnly([.codex], settings: settings)
        let controller = self.makeController(settings: settings)
        defer { controller.releaseStatusItemsForTesting() }
        let monitor = controller.menuCardRefreshMonitor
        let now = Date(timeIntervalSince1970: 1_700_000_000)
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 15,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .codex))
        monitor.beginManualRefresh(frozenModels: [.codex: frozen], provider: .codex)
        defer { monitor.endManualRefresh(for: .codex) }

        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 45,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 65,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7200),
                resetDescription: nil),
            updatedAt: now.addingTimeInterval(1))
        let refreshed = try #require(controller.menuCardModel(for: .codex))

        #expect(!monitor.publishResolvedModelIfCompatible(for: .codex))
        #expect(monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.subtitle(
            for: .codex,
            fallback: MenuCardLiveSubtitle(text: "old", style: .info)).style == .loading)
        #expect(monitor.model(for: .codex, fallback: frozen).metrics.map(\.percent) == frozen.metrics.map(\.percent))

        monitor.endManualRefresh(for: .codex)
        let reconciled = monitor.model(for: .codex, fallback: refreshed)
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(reconciled.metrics.map(\.percent) == refreshed.metrics.map(\.percent))
        if ProcessInfo.processInfo.environment["CODEXBAR_REFRESH_PROBE"] == "1" {
            print(
                "CODEXBAR_REFRESH_PROBE incompatible coreRows=\(refreshed.metrics.count) " +
                    "blockedState=refreshing reconciledState=published")
        }
    }

    @Test
    func `refresh monitor publishes compatible core error honestly`() throws {
        let settings = self.makeSettings()
        self.enableOnly([.codex], settings: settings)
        let controller = self.makeController(settings: settings)
        defer { controller.releaseStatusItemsForTesting() }
        let monitor = controller.menuCardRefreshMonitor
        let now = Date(timeIntervalSince1970: 1_700_000_000)
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 20,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .codex))
        monitor.beginManualRefresh(frozenModels: [.codex: frozen], provider: .codex)
        defer { monitor.endManualRefresh(for: .codex) }

        controller.store.errors[.codex] = "Synthetic core refresh failure"

        #expect(monitor.publishResolvedModelIfCompatible(for: .codex))
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        let subtitle = monitor.subtitle(
            for: .codex,
            fallback: MenuCardLiveSubtitle(text: "old", style: .info))
        #expect(subtitle.style == .error)
        #expect(monitor.model(for: .codex, fallback: frozen).metrics.map(\.percent) == frozen.metrics.map(\.percent))
    }

    @Test
    func `manual refresh keeps frozen quota even if menu rebuilds before completion`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let now = Date()
        for provider in [UsageProvider.claude, .codex] {
            controller.store.snapshots[provider.instanceID] = UsageSnapshot(
                primary: RateWindow(
                    usedPercent: 21,
                    windowMinutes: 300,
                    resetsAt: now.addingTimeInterval(3600),
                    resetDescription: nil),
                secondary: nil,
                updatedAt: now)
            let frozen = try #require(controller.menuCardModel(for: provider))
            controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [provider: frozen])
            controller.store.refreshingProviders.insert(provider.instanceID)

            controller.store.snapshots[provider.instanceID] = UsageSnapshot(
                primary: RateWindow(
                    usedPercent: 18,
                    windowMinutes: 300,
                    resetsAt: now.addingTimeInterval(3600),
                    resetDescription: nil),
                secondary: nil,
                updatedAt: now.addingTimeInterval(1))
            let rebuiltFallback = try #require(controller.menuCardModel(for: provider))
            let inFlight = controller.menuCardRefreshMonitor.model(for: provider, fallback: rebuiltFallback)

            #expect(frozen.metrics.first?.percentLabel == "79% left")
            #expect(rebuiltFallback.metrics.first?.percentLabel == "82% left")
            #expect(inFlight.metrics.first?.percentLabel == "79% left")

            controller.menuCardRefreshMonitor.endManualRefresh()
            controller.store.refreshingProviders.remove(provider.instanceID)
            let completed = controller.menuCardRefreshMonitor.model(for: provider, fallback: frozen)
            #expect(completed.metrics.first?.percentLabel == "82% left")
        }
    }

    @Test
    func `manual refresh uses fallback when frozen quota layout is incompatible`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let now = Date()
        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 21,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .claude))
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [.claude: frozen])
        controller.store.refreshingProviders.insert(.claude)
        defer { controller.store.refreshingProviders.remove(.claude) }

        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 18,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 12,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7 * 24 * 60 * 60),
                resetDescription: nil),
            updatedAt: now.addingTimeInterval(1))
        let rebuiltFallback = try #require(controller.menuCardModel(for: .claude))
        let inFlight = controller.menuCardRefreshMonitor.model(for: .claude, fallback: rebuiltFallback)

        #expect(frozen.metrics.count == 1)
        #expect(rebuiltFallback.metrics.count == 2)
        #expect(inFlight.metrics.count == 2)
        #expect(inFlight.metrics.map(\.id) == rebuiltFallback.metrics.map(\.id))
    }

    @Test
    func `manual refresh preserves frozen quota when supplemental metric remains`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(
            settings: settings,
            account: AccountInfo(email: "test@example.com", plan: "pro"))
        let now = Date()
        controller.store.openAIDashboard = OpenAIDashboardSnapshot(
            signedInEmail: "test@example.com",
            codeReviewRemainingPercent: 88,
            creditEvents: [],
            dailyBreakdown: [],
            usageBreakdown: [],
            creditsPurchaseURL: nil,
            updatedAt: now)
        controller.store.openAIDashboardAttachmentAuthorized = true
        controller.store.openAIDashboardRequiresLogin = false
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 21,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: RateWindow(
                usedPercent: 12,
                windowMinutes: 10080,
                resetsAt: now.addingTimeInterval(7 * 24 * 60 * 60),
                resetDescription: nil),
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .codex))
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [.codex: frozen])
        controller.store.refreshingProviders.insert(.codex)
        defer { controller.store.refreshingProviders.remove(.codex) }

        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: now.addingTimeInterval(1))
        let fallback = try #require(controller.menuCardModel(for: .codex))
        let inFlight = controller.menuCardRefreshMonitor.model(for: .codex, fallback: fallback)

        #expect(frozen.metrics.count == 3)
        #expect(fallback.metrics.map(\.id) == ["code-review"])
        #expect(inFlight.metrics.map(\.id) == frozen.metrics.map(\.id))
        #expect(inFlight.metrics.first?.percentLabel == "79% left")
    }

    @Test
    func `manual refresh uses fallback when empty quota gains credit content`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(
            settings: settings,
            account: AccountInfo(email: "test@example.com", plan: "pro"))
        let now = Date()
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 21,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .codex))
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [.codex: frozen])
        controller.store.refreshingProviders.insert(.codex)
        defer { controller.store.refreshingProviders.remove(.codex) }

        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: now.addingTimeInterval(1))
        controller.store.credits = CreditsSnapshot(
            remaining: 42,
            events: [],
            updatedAt: now.addingTimeInterval(1))
        let fallback = try #require(controller.menuCardModel(for: .codex))
        let inFlight = controller.menuCardRefreshMonitor.model(for: .codex, fallback: fallback)

        #expect(frozen.metrics.count == 1)
        #expect(fallback.metrics.isEmpty)
        #expect(fallback.creditsText != nil)
        #expect(inFlight.metrics.isEmpty)
        #expect(inFlight.creditsText == fallback.creditsText)
    }
}

extension StatusMenuPersistentRefreshTests {
    @Test
    func `manual refresh uses fallback when empty quota gains a placeholder`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let now = Date()
        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 21,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        let frozen = try #require(controller.menuCardModel(for: .claude))
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [.claude: frozen])

        controller.store.snapshots.removeValue(forKey: .claude)
        let fallback = try #require(controller.menuCardModel(for: .claude))
        controller.store.refreshingProviders.insert(.claude)
        defer { controller.store.refreshingProviders.remove(.claude) }
        let inFlight = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)

        #expect(frozen.metrics.count == 1)
        #expect(fallback.metrics.isEmpty)
        #expect(fallback.placeholder != nil)
        #expect(inFlight.metrics.isEmpty)
        #expect(inFlight.placeholder == fallback.placeholder)
    }

    @Test
    func `refresh monitor updates single line credit balances`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(
            settings: settings,
            account: AccountInfo(email: "test@example.com", plan: "pro"))
        let now = Date()
        controller.store.snapshots[.codex] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 10,
                windowMinutes: 300,
                resetsAt: now.addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: now)
        controller.store.credits = CreditsSnapshot(remaining: 80, events: [], updatedAt: now)
        let fallback = try #require(controller.menuCardModel(for: .codex))

        controller.store.credits = CreditsSnapshot(
            remaining: 42,
            events: [],
            updatedAt: now.addingTimeInterval(1))
        let refreshed = controller.menuCardRefreshMonitor.model(for: .codex, fallback: fallback)

        #expect(refreshed.creditsRemaining == 42)
        #expect(refreshed.creditsText != fallback.creditsText)
    }

    @Test
    func `refresh monitor preserves multiline workspace credit text`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        controller.store.snapshots[.amp] = AmpUsageSnapshot(
            freeQuota: nil,
            freeUsed: nil,
            hourlyReplenishment: nil,
            windowHours: nil,
            individualCredits: 12,
            workspaceBalances: [AmpWorkspaceBalance(name: "Team", remaining: 7)],
            updatedAt: Date()).toUsageSnapshot()
        let fallback = try #require(controller.menuCardModel(for: .amp))

        controller.store.snapshots[.amp] = AmpUsageSnapshot(
            freeQuota: nil,
            freeUsed: nil,
            hourlyReplenishment: nil,
            windowHours: nil,
            individualCredits: 10,
            workspaceBalances: [AmpWorkspaceBalance(name: "Team", remaining: 3)],
            updatedAt: Date()).toUsageSnapshot()
        let refreshed = controller.menuCardRefreshMonitor.model(for: .amp, fallback: fallback)

        #expect(refreshed.providerDetails == fallback.providerDetails)
    }

    @Test
    func `refresh monitor preserves tracked layout when refresh adds usage sections`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let fallback = try #require(controller.menuCardModel(for: .claude))
        #expect(fallback.metrics.isEmpty)

        controller.store.snapshots[.claude] = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 25,
                windowMinutes: 300,
                resetsAt: Date().addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: Date())

        let refreshed = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)

        #expect(refreshed.metrics.isEmpty)
        #expect(refreshed.placeholder == fallback.placeholder)
    }

    @Test
    func `refresh monitor preserves tracked layout when token error appears`() throws {
        let settings = self.makeSettings()
        settings.costUsageEnabled = true
        settings.costSummaryDisplayStyle = .both
        let controller = self.makeController(settings: settings)
        controller.store._setTokenSnapshotForTesting(Self.makeTokenSnapshot(), provider: .claude)
        let fallback = try #require(controller.menuCardModel(for: .claude))
        #expect(fallback.tokenUsage?.errorLine == nil)

        controller.store._setTokenErrorForTesting("New token usage error", provider: .claude)
        let refreshed = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)

        #expect(refreshed.tokenUsage?.errorLine == nil)
    }

    @Test
    func `refresh monitor preserves tracked layout when token error text changes`() throws {
        let settings = self.makeSettings()
        settings.costUsageEnabled = true
        settings.costSummaryDisplayStyle = .both
        let controller = self.makeController(settings: settings)
        controller.store._setTokenSnapshotForTesting(Self.makeTokenSnapshot(), provider: .claude)
        controller.store._setTokenErrorForTesting("Old token usage error", provider: .claude)
        let fallback = try #require(controller.menuCardModel(for: .claude))

        controller.store._setTokenErrorForTesting(
            "A longer replacement error that could occupy more lines",
            provider: .claude)
        let refreshed = controller.menuCardRefreshMonitor.model(for: .claude, fallback: fallback)

        #expect(refreshed.tokenUsage?.errorLine == "Old token usage error")
    }

    @Test
    func `live subtitle preserves canonical model error filtering`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(
            settings: settings,
            account: AccountInfo(email: "test@example.com", plan: "pro"))
        controller.store.errors[.codex] = UsageError.noRateLimitsFound.errorDescription
        let model = try #require(controller.menuCardModel(for: .codex))
        let fallback = MenuCardLiveSubtitle(text: "Fallback", style: .error)

        let liveSubtitle = controller.menuCardRefreshMonitor.subtitle(for: .codex, fallback: fallback)

        #expect(liveSubtitle.text == model.subtitleText)
        #expect(liveSubtitle.style == model.subtitleStyle)
        #expect(liveSubtitle.text != UsageError.noRateLimitsFound.errorDescription)
        #expect(liveSubtitle.style != .error)
    }

    @Test
    func `override cards keep their own subtitle`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let liveModel = try #require(controller.menuCardModel(for: .codex))
        let overrideModel = try #require(controller.menuCardModel(
            for: .codex,
            errorOverride: "Account unavailable",
            forceOverrideCard: true))

        #expect(liveModel.usesLiveSubtitle)
        #expect(!overrideModel.usesLiveSubtitle)
        #expect(overrideModel.subtitleText == "Account unavailable")
    }

    @Test
    func `live failure keeps the measured card height`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)

        func fittingHeight(for model: UsageMenuCardView.Model) -> CGFloat {
            NSHostingView(rootView: UsageMenuCardView(model: model, width: 320)
                .environment(\.menuCardRefreshMonitor, controller.menuCardRefreshMonitor))
                .fittingSize.height
        }

        let idleModel = try #require(controller.menuCardModel(for: .codex))
        let idleHeight = fittingHeight(for: idleModel)
        controller.store.errors[.codex] = "Short error"
        let failureHeight = fittingHeight(for: idleModel)

        #expect(failureHeight == idleHeight)

        let errorModel = try #require(controller.menuCardModel(for: .codex))
        let errorHeight = fittingHeight(for: errorModel)
        controller.store.errors[.codex] =
            "Refresh failed with a much longer replacement message that must not resize the tracked menu"
        let replacementErrorHeight = fittingHeight(for: errorModel)
        controller.menuCardRefreshMonitor.beginManualRefresh(frozenModels: [:], provider: nil)
        let retryHeight = fittingHeight(for: errorModel)

        #expect(replacementErrorHeight == errorHeight)
        let fallback = MenuCardLiveSubtitle(text: errorModel.subtitleText, style: errorModel.subtitleStyle)
        #expect(controller.menuCardRefreshMonitor.subtitle(for: .codex, fallback: fallback).style == .error)
        controller.store.refreshingProviders.insert(.codex)
        #expect(controller.menuCardRefreshMonitor.subtitle(for: .codex, fallback: fallback).style == .loading)
        controller.store.refreshingProviders.remove(.codex)
        #expect(retryHeight == errorHeight)
    }

    @Test
    func `manual refresh is suppressed after shutdown preparation`() {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        var requestCount = 0
        controller._test_manualRefreshOperation = {
            requestCount += 1
        }

        controller.prepareForAppShutdown()
        controller.refreshNow()

        #expect(requestCount == 0)
        #expect(controller.manualRefreshTasks.isEmpty)
        #expect(!controller.menuCardRefreshMonitor.isManualRefreshInFlight)
    }

    @Test
    func `repeated manual refresh clicks share one lifecycle`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)

        let gate = ManualRefreshGate()
        var requestCount = 0
        controller._test_manualRefreshOperation = {
            requestCount += 1
            await gate.wait()
        }

        controller.refreshNow()
        let task = try #require(controller.manualRefreshTasks[.global])
        controller.refreshNow()
        controller.refreshNow()
        await Task.yield()

        #expect(requestCount == 1)
        #expect(controller.menuCardRefreshMonitor.isManualRefreshInFlight)

        gate.resume()
        await task.value

        #expect(controller.manualRefreshTasks[.global] == nil)
        #expect(!controller.menuCardRefreshMonitor.isManualRefreshInFlight)
    }

    @Test
    func `provider menu persistent refresh row and command R refresh only that provider`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnly([.claude, .codex], settings: settings)

        let controller = self.makeController(settings: settings)
        let menu = try #require(controller.makeMenu(for: .claude) as? StatusItemMenu)
        let codexMenu = try #require(controller.makeMenu(for: .codex) as? StatusItemMenu)
        controller.menuWillOpen(menu)
        controller.menuWillOpen(codexMenu)
        defer {
            controller.menuDidClose(codexMenu)
            controller.menuDidClose(menu)
        }

        let mouseGate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await mouseGate.wait() }
        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(controller.isPersistentRefreshItem(refreshItem))
        let refreshView = try #require(refreshItem.view as? PersistentRefreshMenuView)
        #expect(refreshView.accessibilityPerformPress())
        for _ in 0..<20 where controller.manualRefreshTasks[.provider(.claude)] == nil {
            await Task.yield()
        }
        let mouseTask = try #require(controller.manualRefreshTasks[.provider(.claude)])

        // Refreshing Claude greys the Claude row but must leave the Codex row available.
        #expect(controller.isRefreshActionInFlight(for: menu))
        #expect(!controller.isRefreshActionInFlight(for: codexMenu))

        mouseGate.resume()
        await mouseTask.value

        let keyboardGate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await keyboardGate.wait() }
        #expect(try menu.performKeyEquivalent(with: self.keyEvent("r", keyCode: 15)))
        for _ in 0..<20 where controller.manualRefreshTasks[.provider(.claude)] == nil {
            await Task.yield()
        }
        let keyboardTask = try #require(controller.manualRefreshTasks[.provider(.claude)])
        keyboardGate.resume()
        await keyboardTask.value
    }

    @Test
    func `provider menu does not replace matching scoped refresh`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnly([.claude, .codex], settings: settings)

        let controller = self.makeController(settings: settings)
        let menu = try #require(controller.makeMenu(for: .claude) as? StatusItemMenu)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        controller.store.refreshingProviders.insert(.claude)
        var requestCount = 0
        controller._test_manualRefreshOperation = { requestCount += 1 }

        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(controller.isPersistentRefreshItem(refreshItem))
        controller.performPersistentRefreshAction(in: ObjectIdentifier(menu))
        #expect(try menu.performKeyEquivalent(with: self.keyEvent("r", keyCode: 15)))
        for _ in 0..<20 {
            await Task.yield()
        }

        #expect(requestCount == 0)
        #expect(controller.manualRefreshTasks.isEmpty)
    }

    @Test
    func `merged overview refreshes globally while selected provider stays scoped`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnly([.claude, .codex], settings: settings)
        settings.mergedMenuLastSelectedWasOverview = true

        let controller = self.makeController(settings: settings)
        let menu = try #require(controller.makeMenu() as? StatusItemMenu)
        controller.mergedMenu = menu
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        let overviewGate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await overviewGate.wait() }
        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        #expect(controller.isPersistentRefreshItem(refreshItem))
        controller.performPersistentRefreshAction(in: ObjectIdentifier(menu))
        for _ in 0..<20 where controller.manualRefreshTasks[.global] == nil {
            await Task.yield()
        }
        let overviewTask = try #require(controller.manualRefreshTasks[.global])
        overviewGate.resume()
        await overviewTask.value

        settings.mergedMenuLastSelectedWasOverview = false
        controller.selectedMenuProvider = .claude
        let providerGate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await providerGate.wait() }
        #expect(try menu.performKeyEquivalent(with: self.keyEvent("r", keyCode: 15)))
        for _ in 0..<20 where controller.manualRefreshTasks[.provider(.claude)] == nil {
            await Task.yield()
        }
        let providerTask = try #require(controller.manualRefreshTasks[.provider(.claude)])
        providerGate.resume()
        await providerTask.value
    }

    @Test
    func `provider scoped refresh updates status and widget snapshot`() async {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.statusChecksEnabled = true
        self.enableOnly([.synthetic], settings: settings)

        let controller = self.makeController(settings: settings)
        controller.store._test_providerRefreshOverride = { _ in }
        controller.store._test_providerStatusFetchOverride = { provider in
            #expect(provider == .synthetic)
            return ProviderStatus(indicator: .none, description: "Operational", updatedAt: Date())
        }
        var savedSnapshots = 0
        controller.store._test_widgetSnapshotSaveOverride = { _ in
            savedSnapshots += 1
        }

        await controller.performStoreRefresh(
            for: .synthetic,
            refreshOpenMenusWhenComplete: false,
            interaction: .userInitiated)
        _ = await controller.store.widgetSnapshotPersistTask?.result

        #expect(controller.store.statuses[.synthetic]?.description == "Operational")
        #expect(savedSnapshots == 1)
    }

    @Test
    func `failed manual refresh returns persistent item to enabled and surfaces error`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)
        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)
        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        let gate = ManualRefreshGate()

        controller._test_manualRefreshOperation = {
            await gate.wait()
            controller.store.errors[.codex] = "Refresh failed"
        }

        controller.refreshNow()
        let task = try #require(controller.manualRefreshTasks[.global])
        #expect(!refreshItem.isEnabled)

        gate.resume()
        await task.value

        #expect(controller.manualRefreshTasks[.global] == nil)
        #expect(refreshItem.isEnabled)
        let fallback = MenuCardLiveSubtitle(text: "Fallback", style: .info)
        #expect(controller.menuCardRefreshMonitor.subtitle(for: .codex, fallback: fallback).style == .error)
    }

    @Test
    func `status item menu intercepts persistent shortcuts without native item selection`() throws {
        let menu = StatusItemMenu()
        let recorder = RefreshShortcutRecorder()
        menu.persistentActionDelegate = recorder
        menu.menuInteractionGeneration = 42

        #expect(try menu.performKeyEquivalent(with: self.keyEvent("r", keyCode: 15)) == true)
        #expect(try menu.performKeyEquivalent(with: self.keyEvent(",", keyCode: 43)) == true)
        #expect(try menu.performKeyEquivalent(with: self.keyEvent("q", keyCode: 12)) == true)

        #expect(recorder.refreshCount == 1)
        #expect(recorder.refreshMenuIDs == [ObjectIdentifier(menu)])
        #expect(recorder.refreshMenuInteractionGenerations == [42])
        #expect(recorder.settingsCount == 1)
        #expect(recorder.quitCount == 1)
    }
}

extension StatusMenuPersistentRefreshTests {
    private func keyEvent(_ characters: String, keyCode: UInt16) throws -> NSEvent {
        try #require(NSEvent.keyEvent(
            with: .keyDown,
            location: .zero,
            modifierFlags: [.command],
            timestamp: 0,
            windowNumber: 0,
            context: nil,
            characters: characters,
            charactersIgnoringModifiers: characters,
            isARepeat: false,
            keyCode: keyCode))
    }

    @Test
    func `refresh row metrics match tuned native-style values`() {
        let metrics = PersistentRefreshRowMetrics.defaults
        #expect(metrics.rowHeight == 24)
        #expect(metrics.selectionHorizontalInset == 5)
        #expect(metrics.selectionVerticalInset == 0)
        #expect(metrics.selectionCornerRadius == 7)
        #expect(metrics.leadingPadding == 15)
        #expect(metrics.trailingPadding == 8)
        #expect(metrics.iconWidth == 16)
        #expect(metrics.iconSymbolPointSize == 16)
        #expect(metrics.iconSymbolWeight == .regular)
        #expect(metrics.iconTitleSpacing == 4.5)
        #expect(metrics.shortcutFontSize == 13)
        #expect(metrics.shortcutXOffset == -9.5)
        #expect(metrics.shortcutYOffset == 0)
    }

    @Test
    func `refresh shortcut display has stable native-style column`() throws {
        let previousRendering = StatusItemController.menuCardRenderingEnabled
        StatusItemController.menuCardRenderingEnabled = true
        defer { StatusItemController.menuCardRenderingEnabled = previousRendering }

        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false

        let controller = self.makeController(settings: settings)
        let menu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(menu)

        let refreshItem = try #require(menu.items.first { $0.title == "Refresh" })
        let refreshView = try #require(refreshItem.view as? PersistentRefreshMenuView)
        refreshView.applySize(width: 320, height: PersistentRefreshRowMetrics.defaults.rowHeight)
        refreshView.layoutSubtreeIfNeeded()

        let shortcutField = try #require(
            refreshView.subviews.compactMap { $0 as? NSTextField }.first { $0.stringValue == "⌘ R" })
        #expect(shortcutField.alignment == .left)
        #expect(shortcutField.lineBreakMode == .byClipping)
        #expect(shortcutField.frame.width >= 40)
        let shortcutFont = try #require(shortcutField.font)
        #expect(abs(shortcutFont.pointSize - PersistentRefreshRowMetrics.defaults.shortcutFontSize) < 0.001)

        let iconView = try #require(refreshView.subviews.compactMap { $0 as? NSImageView }.first)
        let titleField = try #require(
            refreshView.subviews.compactMap { $0 as? NSTextField }.first { $0.stringValue == "Refresh" })
        #expect(iconView.frame.minX == PersistentRefreshRowMetrics.defaults.leadingPadding)
        #expect(titleField.frame.minX == PersistentRefreshRowMetrics.defaults.leadingPadding
            + PersistentRefreshRowMetrics.defaults.iconWidth
            + PersistentRefreshRowMetrics.defaults.iconTitleSpacing)
        #expect(iconView.frame.width == PersistentRefreshRowMetrics.defaults.iconWidth)
        #expect(iconView.frame.height == PersistentRefreshRowMetrics.defaults.iconWidth)
    }

    @Test
    func `refresh row width follows final rendered menu width`() {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        defer { controller.releaseStatusItemsForTesting() }

        let metrics = PersistentRefreshRowMetrics.defaults
        let refreshView = PersistentRefreshMenuView(
            title: "Refresh",
            systemImageName: "arrow.clockwise",
            shortcutText: "⌘ R")
        refreshView.applySize(width: StatusItemController.menuCardBaseWidth, height: metrics.rowHeight)
        refreshView.frame.origin.x = 4

        let refreshItem = NSMenuItem()
        refreshItem.title = "Refresh"
        refreshItem.view = refreshView

        let wideNativeItem = NSMenuItem(
            title: String(repeating: "W", count: 60),
            action: nil,
            keyEquivalent: "")
        let menu = NSMenu()
        menu.addItem(refreshItem)
        menu.addItem(wideNativeItem)

        let expectedWidth = controller.renderedMenuWidth(for: menu)
        #expect(expectedWidth > StatusItemController.menuCardBaseWidth)

        controller.refreshMenuCardHeights(in: menu)

        #expect(abs(refreshView.frame.width - expectedWidth) <= 0.5)
        #expect(refreshView.frame.origin == .zero)
        #expect(refreshView.frame.height == metrics.rowHeight)
    }
}

extension StatusMenuPersistentRefreshTests {
    @Test
    func `global manual refresh only marks active provider cards as refreshing`() {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let monitor = controller.menuCardRefreshMonitor
        let fallback = MenuCardLiveSubtitle(text: "Idle", style: .info)

        monitor.beginManualRefresh(frozenModels: [:], provider: nil)
        defer { monitor.endManualRefresh() }

        controller.store.refreshingProviders.insert(.claude)
        #expect(monitor.isManualRefreshInFlight)
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.isManualRefreshInFlight(for: .claude))
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)
        #expect(monitor.subtitle(for: .claude, fallback: fallback).style == .loading)

        controller.store.refreshingProviders.remove(.claude)
        #expect(monitor.isManualRefreshInFlight)
        #expect(!monitor.isManualRefreshInFlight(for: .claude))
        #expect(monitor.subtitle(for: .claude, fallback: fallback).style == .info)
    }

    @Test
    func `completed provider cards stop refreshing while another provider is still running`() async {
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.costUsageEnabled = false
        settings.openAIWebAccessEnabled = false
        settings.codexCookieSource = .off
        self.enableOnly([.claude, .codex], settings: settings)
        let controller = self.makeController(settings: settings)
        let claudeStarted = ManualRefreshGate()
        let releaseClaude = ManualRefreshGate()
        let monitor = controller.menuCardRefreshMonitor
        let fallback = MenuCardLiveSubtitle(text: "Idle", style: .info)

        controller.store._test_providerRefreshOverride = { provider in
            guard provider == .claude else { return }
            claudeStarted.resume()
            await releaseClaude.wait()
        }
        defer { controller.store._test_providerRefreshOverride = nil }

        controller.refreshNow()
        await claudeStarted.wait()
        for _ in 0..<20 where controller.store.refreshingProviders != [.claude] {
            await Task.yield()
        }

        #expect(controller.store.refreshingProviders == [.claude])
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.isManualRefreshInFlight(for: .claude))
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)
        #expect(monitor.subtitle(for: .claude, fallback: fallback).style == .loading)

        releaseClaude.resume()
        await controller.manualRefreshTasks[.global]?.value
    }

    @Test
    func `token-cost tail does not keep completed provider card refreshing`() async {
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.costUsageEnabled = true
        settings.openAIWebAccessEnabled = false
        settings.codexCookieSource = .off
        self.enableOnly([.codex], settings: settings)
        let controller = self.makeController(settings: settings)
        let tokenRefreshStarted = ManualRefreshGate()
        let releaseTokenRefresh = ManualRefreshGate()
        defer { releaseTokenRefresh.resume() }
        let monitor = controller.menuCardRefreshMonitor
        let fallback = MenuCardLiveSubtitle(text: "Idle", style: .info)
        let menu = controller.makeMenu()
        var tokenRefreshWasForced: Bool?

        controller.store._test_providerRefreshOverride = { _ in }
        controller.store._test_codexCreditsLoaderOverride = {
            CreditsSnapshot(remaining: 25, events: [], updatedAt: Date())
        }
        controller.store._test_tokenUsageRefreshOverride = { _, force in
            tokenRefreshWasForced = force
            tokenRefreshStarted.resume()
            await releaseTokenRefresh.wait()
        }
        defer {
            controller.store._test_providerRefreshOverride = nil
            controller.store._test_codexCreditsLoaderOverride = nil
            controller.store._test_tokenUsageRefreshOverride = nil
        }

        controller.refreshNow()
        let manualTask = controller.manualRefreshTasks[.global]
        #expect(await tokenRefreshStarted.waitUntilSignaled())
        let manualCompletion = RefreshCompletionProbe()
        let manualCompletionTask = Task {
            await manualTask?.value
            await manualCompletion.markCompleted()
        }
        #expect(await manualCompletion.waitUntilCompleted())
        let tailTask = controller.store.forcedRefreshEnrichmentTask

        #expect(!controller.store.isRefreshing)
        #expect(controller.store.hasForcedRefreshEnrichmentInFlight)
        #expect(controller.store.refreshingProviders.isEmpty)
        #expect(tokenRefreshWasForced == true)
        #expect(controller.isRefreshActionInFlight(for: menu))
        #expect(!monitor.isManualRefreshInFlight)
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)

        releaseTokenRefresh.resume()
        await manualCompletionTask.value
        await tailTask?.value
        #expect(!controller.store.hasForcedRefreshEnrichmentInFlight)
        #expect(!controller.isRefreshActionInFlight(for: menu))
    }

    @Test
    func `credit tail does not keep completed provider card refreshing`() async {
        await self.verifyCompletedProviderCardStopsRefreshing(whileBlocking: .credits)
    }

    @Test
    func `dashboard tail does not keep completed provider card refreshing`() async {
        await self.verifyCompletedProviderCardStopsRefreshing(whileBlocking: .dashboard)
    }

    private func verifyCompletedProviderCardStopsRefreshing(whileBlocking stage: BlockingEnrichmentStage) async {
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.costUsageEnabled = false
        settings.openAIWebAccessEnabled = stage == .dashboard
        settings.codexCookieSource = stage == .dashboard ? .auto : .off
        settings._test_liveSystemCodexAccount = ObservedSystemCodexAccount(
            email: "fixture@example.com",
            codexHomePath: "/Users/test/.codex",
            observedAt: Date(),
            identity: .emailOnly(normalizedEmail: "fixture@example.com"))
        settings.codexActiveSource = .liveSystem
        self.enableOnly([.codex], settings: settings)
        let account = AccountInfo(email: "fixture@example.com", plan: "pro")
        let controller = self.makeController(settings: settings, account: account)
        controller.store.accountInfoCache[.codex] = UsageStore.AccountInfoCacheEntry(
            account: account,
            configRevision: settings.configRevision,
            expiresAt: .distantFuture)
        let stageStarted = ManualRefreshGate()
        let releaseStage = ManualRefreshGate()
        defer {
            releaseStage.resume()
            controller.prepareForAppShutdown()
            settings._test_liveSystemCodexAccount = nil
        }
        let monitor = controller.menuCardRefreshMonitor
        let fallback = MenuCardLiveSubtitle(text: "Idle", style: .info)
        let menu = controller.makeMenu()
        var creditsLoaderCalls = 0
        var dashboardLoaderCalls = 0

        controller.store._test_providerRefreshOverride = { _ in }
        controller.store._test_codexCreditsLoaderOverride = {
            creditsLoaderCalls += 1
            if stage == .credits, creditsLoaderCalls == 1 {
                stageStarted.resume()
                await releaseStage.wait()
            }
            return CreditsSnapshot(remaining: 25, events: [], updatedAt: Date())
        }
        controller.store._test_openAIDashboardLoaderOverride = { _, _, _, _ in
            dashboardLoaderCalls += 1
            if stage == .dashboard, dashboardLoaderCalls == 1 {
                stageStarted.resume()
                await releaseStage.wait()
            }
            return OpenAIDashboardSnapshot(
                signedInEmail: account.email,
                codeReviewRemainingPercent: 95,
                creditEvents: [],
                dailyBreakdown: [],
                usageBreakdown: [],
                creditsPurchaseURL: nil,
                creditsRemaining: 25,
                accountPlan: "Pro",
                updatedAt: Date())
        }
        defer {
            controller.store._test_providerRefreshOverride = nil
            controller.store._test_codexCreditsLoaderOverride = nil
            controller.store._test_openAIDashboardLoaderOverride = nil
        }

        controller.refreshNow()
        let manualTask = controller.manualRefreshTasks[.global]
        let didStartStage = await stageStarted.waitUntilSignaled()
        #expect(didStartStage)
        guard didStartStage else { return }
        let manualCompletion = RefreshCompletionProbe()
        let manualCompletionTask = Task {
            await manualTask?.value
            await manualCompletion.markCompleted()
        }
        let didCompleteManualRefresh = await manualCompletion.waitUntilCompleted()
        #expect(didCompleteManualRefresh)
        guard didCompleteManualRefresh else { return }
        let tailTask = controller.store.forcedRefreshEnrichmentTask

        #expect(!controller.store.isRefreshing)
        #expect(controller.store.hasForcedRefreshEnrichmentInFlight)
        #expect(controller.store.refreshingProviders.isEmpty)
        #expect(controller.isRefreshActionInFlight(for: menu))
        #expect(!monitor.isManualRefreshInFlight)
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        #expect(monitor.subtitle(for: .codex, fallback: fallback).style == .info)

        releaseStage.resume()
        await manualCompletionTask.value
        let tailCompletion = RefreshCompletionProbe()
        let tailCompletionTask = Task {
            await tailTask?.value
            await tailCompletion.markCompleted()
        }
        let didCompleteTail = await tailCompletion.waitUntilCompleted()
        #expect(didCompleteTail)
        guard didCompleteTail else { return }
        await tailCompletionTask.value

        #expect(creditsLoaderCalls >= 1)
        #expect(dashboardLoaderCalls == (stage == .dashboard ? 1 : 0))
        #expect(!controller.store.hasForcedRefreshEnrichmentInFlight)
        #expect(!controller.isRefreshActionInFlight(for: menu))
    }

    @Test
    func `provider scoped refresh waits for global forced enrichment`() async {
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.costUsageEnabled = true
        settings.openAIWebAccessEnabled = false
        settings.codexCookieSource = .off
        self.enableOnly([.codex], settings: settings)
        let controller = self.makeController(settings: settings)
        let tokenRefreshStarted = ManualRefreshGate()
        let releaseTokenRefresh = ManualRefreshGate()
        let scopedWaitStarted = ManualRefreshGate()
        defer { releaseTokenRefresh.resume() }
        var providerRefreshCalls = 0
        var tokenRefreshCalls = 0

        controller.store._test_providerRefreshOverride = { _ in
            providerRefreshCalls += 1
        }
        controller.store._test_codexCreditsLoaderOverride = {
            CreditsSnapshot(remaining: 25, events: [], updatedAt: Date())
        }
        controller.store._test_tokenUsageRefreshOverride = { _, _ in
            tokenRefreshCalls += 1
            if tokenRefreshCalls == 1 {
                tokenRefreshStarted.resume()
                await releaseTokenRefresh.wait()
            }
        }
        controller.store._test_forcedRefreshEnrichmentWaitObserver = {
            scopedWaitStarted.resume()
        }
        defer {
            controller.store._test_providerRefreshOverride = nil
            controller.store._test_codexCreditsLoaderOverride = nil
            controller.store._test_tokenUsageRefreshOverride = nil
            controller.store._test_forcedRefreshEnrichmentWaitObserver = nil
        }

        controller.refreshNow()
        let globalTask = controller.manualRefreshTasks[.global]
        #expect(await tokenRefreshStarted.waitUntilSignaled())
        let globalCompletion = RefreshCompletionProbe()
        let globalCompletionTask = Task {
            await globalTask?.value
            await globalCompletion.markCompleted()
        }
        #expect(await globalCompletion.waitUntilCompleted())
        #expect(providerRefreshCalls == 1)

        let scopedTask = Task { @MainActor in
            await controller.performStoreRefresh(
                for: .codex,
                refreshOpenMenusWhenComplete: false,
                interaction: .userInitiated)
        }
        #expect(await scopedWaitStarted.waitUntilSignaled())
        #expect(providerRefreshCalls == 1)

        releaseTokenRefresh.resume()
        await globalCompletionTask.value
        await scopedTask.value
        #expect(providerRefreshCalls == 2)
        #expect(tokenRefreshCalls == 2)
        #expect(!controller.store.hasForcedRefreshEnrichmentInFlight)
    }

    @Test
    func `concurrent manual refreshes keep each provider's frozen card`() throws {
        let settings = self.makeSettings()
        let controller = self.makeController(settings: settings)
        let monitor = controller.menuCardRefreshMonitor
        let now = Date()

        func quotaSnapshot(usedPercent: Double, updatedAt: Date) -> UsageSnapshot {
            UsageSnapshot(
                primary: RateWindow(
                    usedPercent: usedPercent,
                    windowMinutes: 300,
                    resetsAt: updatedAt.addingTimeInterval(3600),
                    resetDescription: nil),
                secondary: nil,
                updatedAt: updatedAt)
        }

        // The snapshot helper supplies every enabled provider even for a provider-scoped refresh.
        controller.store.snapshots[.claude] = quotaSnapshot(usedPercent: 21, updatedAt: now)
        controller.store.snapshots[.codex] = quotaSnapshot(usedPercent: 15, updatedAt: now)
        let claudeFrozen = try #require(controller.menuCardModel(for: .claude))
        let codexBeforeItsRefresh = try #require(controller.menuCardModel(for: .codex))
        monitor.beginManualRefresh(
            frozenModels: [.claude: claudeFrozen, .codex: codexBeforeItsRefresh],
            provider: .claude)

        // Each provider must freeze the card visible when its own refresh starts.
        controller.store.snapshots[.claude] = quotaSnapshot(usedPercent: 65, updatedAt: now.addingTimeInterval(1))
        controller.store.snapshots[.codex] = quotaSnapshot(usedPercent: 42, updatedAt: now.addingTimeInterval(1))
        let claudeMidRefresh = try #require(controller.menuCardModel(for: .claude))
        let codexFrozen = try #require(controller.menuCardModel(for: .codex))
        monitor.beginManualRefresh(
            frozenModels: [.claude: claudeMidRefresh, .codex: codexFrozen],
            provider: .codex)

        let shownClaude = monitor.model(for: .claude, fallback: claudeMidRefresh)
        let shownCodex = monitor.model(for: .codex, fallback: codexFrozen)
        #expect(shownClaude.metrics.first?.percentLabel == "79% left")
        #expect(shownCodex.metrics.first?.percentLabel == "58% left")

        // Ending Codex leaves Claude frozen; ending Claude clears it.
        monitor.endManualRefresh(for: .codex)
        #expect(monitor.isManualRefreshInFlight(for: .claude))
        #expect(!monitor.isManualRefreshInFlight(for: .codex))
        monitor.endManualRefresh(for: .claude)
        #expect(!monitor.isManualRefreshInFlight(for: .claude))
    }

    @Test
    func `refreshing one provider does not block refreshing another`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnly([.claude, .codex], settings: settings)

        let controller = self.makeController(settings: settings)
        let codexMenu = try #require(controller.makeMenu(for: .codex) as? StatusItemMenu)
        controller.menuWillOpen(codexMenu)
        defer { controller.menuDidClose(codexMenu) }

        // Simulate a Claude manual refresh already in flight.
        controller.manualRefreshTasks[.provider(.claude)] = Task {}
        defer {
            controller.manualRefreshTasks[.provider(.claude)]?.cancel()
            controller.manualRefreshTasks[.provider(.claude)] = nil
        }

        let gate = ManualRefreshGate()
        controller._test_manualRefreshOperation = { await gate.wait() }

        // A Codex refresh must still start rather than being blocked by the in-flight Claude one.
        controller.performPersistentRefreshAction(in: ObjectIdentifier(codexMenu))
        for _ in 0..<20 where controller.manualRefreshTasks[.provider(.codex)] == nil {
            await Task.yield()
        }
        let codexTask = try #require(controller.manualRefreshTasks[.provider(.codex)])
        #expect(controller.isRefreshActionInFlight(for: codexMenu))

        gate.resume()
        await codexTask.value
    }

    @Test
    func `overview stays busy through a provider refresh tail and blocks a global refresh`() async throws {
        let settings = self.makeSettings()
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnly([.claude, .codex], settings: settings)
        settings.mergedMenuLastSelectedWasOverview = true

        let controller = self.makeController(settings: settings)
        let menu = try #require(controller.makeMenu() as? StatusItemMenu)
        controller.mergedMenu = menu
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        // A per-provider Claude refresh whose task outlives the store's `refreshingProviders` window
        // (the status/token/credits tail runs after the provider is removed from that set).
        controller.manualRefreshTasks[.provider(.claude)] = Task {}
        defer {
            controller.manualRefreshTasks[.provider(.claude)]?.cancel()
            controller.manualRefreshTasks[.provider(.claude)] = nil
        }

        // Overview stands for every provider, so its row stays greyed even with `refreshingProviders` empty.
        #expect(controller.store.refreshingProviders.isEmpty)
        #expect(controller.isRefreshActionInFlight(for: menu))

        // And a global overview refresh must not start on top of the in-flight provider refresh.
        var requestCount = 0
        controller._test_manualRefreshOperation = { requestCount += 1 }
        controller.performPersistentRefreshAction(in: ObjectIdentifier(menu))
        for _ in 0..<20 {
            await Task.yield()
        }
        #expect(requestCount == 0)
        #expect(controller.manualRefreshTasks[.global] == nil)
    }
}
