import AppKit
import CodexBarCore
import Foundation
import Testing
@testable import CodexBar

extension StatusMenuTests {
    @Test
    func `opening fresh menu does not schedule deferred refresh`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        var providerRefreshCount = 0
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            refreshInteractions.append(ProviderInteractionContext.current)
            providerRefreshCount += 1
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        StatusItemController.setClosedMenuPreparationDelayForTesting(.zero)
        defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)

        for _ in 0..<20 {
            await Task.yield()
        }
        #expect(providerRefreshCount == 0)
        #expect(!controller.deferredMenuInteractionRefreshPending)

        controller.menuDidClose(menu)
        for _ in 0..<40 {
            await Task.yield()
        }

        #expect(providerRefreshCount == 0)
        #expect(refreshInteractions.isEmpty)
    }

    @Test
    func `non codex menu refresh all also defers codex dashboard refresh`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        settings.refreshAllProvidersOnMenuOpen = true
        // Enable several providers; only the available ones land in background work. The
        // assertion below compares against that resolved set, so it stays robust regardless.
        self.enableProvidersForInstantOpenTesting([.codex, .claude, .factory], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        // Give every enabled provider a fresh, non-stale snapshot so the ONLY reason to refresh on
        // open is the new setting — not a stale/missing retry (which is the pre-existing behavior).
        let now = Date()
        for provider in store.enabledFirstPartyProvidersForBackgroundWork() {
            store._setSnapshotForTesting(
                UsageSnapshot(
                    primary: RateWindow(
                        usedPercent: 20,
                        windowMinutes: 300,
                        resetsAt: now.addingTimeInterval(1800),
                        resetDescription: nil),
                    secondary: nil,
                    updatedAt: now),
                provider: provider)
        }
        var refreshedProviders: Set<UsageProvider> = []
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            refreshedProviders.insert(provider)
            refreshInteractions.append(ProviderInteractionContext.current)
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        StatusItemController.setClosedMenuPreparationDelayForTesting(.zero)
        defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let expectedProviders = Set(store.enabledFirstPartyProvidersForBackgroundWork())
        let menu = controller.makeMenu(for: .claude)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        for _ in 0..<80 where refreshedProviders != expectedProviders {
            await Task.yield()
        }

        // Every enabled provider is refreshed on open even though all snapshots were fresh.
        #expect(refreshedProviders == expectedProviders && expectedProviders.contains(.codex))
        #expect(!refreshInteractions.isEmpty)
        #expect(refreshInteractions.allSatisfy { $0 == .background })
        #expect(controller.deferredOpenAIDashboardRefreshReason != nil)
    }

    @Test
    func `menu open leaves fresh provider untouched when refresh-all-on-open is disabled`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        settings.refreshAllProvidersOnMenuOpen = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        var providerRefreshCount = 0
        store._test_providerRefreshOverride = { _ in
            providerRefreshCount += 1
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        StatusItemController.setClosedMenuPreparationDelayForTesting(.zero)
        defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
        // Let the delayed open-refresh task actually fire; with the setting off and fresh data,
        // it must still skip the refresh (today's stale/missing-only behavior).
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        for _ in 0..<40 {
            await Task.yield()
        }

        #expect(providerRefreshCount == 0)
    }

    @Test
    func `delayed open refresh does not rebuild fresh menu after unrelated data invalidation`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.milliseconds(50))
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        let key = ObjectIdentifier(menu)
        let openedVersion = controller.menuVersions[key]
        var rebuildCount = 0
        controller._test_openMenuRebuildObserver = { _ in
            rebuildCount += 1
        }
        defer { controller._test_openMenuRebuildObserver = nil }

        // Models first-open storage-footprint publication: menu content becomes stale, but no
        // displayed provider was missing or failed when this menu opened.
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)
        try? await Task.sleep(for: .milliseconds(150))

        #expect(controller.menuContentVersion != openedVersion)
        #expect(controller.menuVersions[key] == openedVersion)
        #expect(rebuildCount == 0)
    }

    @Test
    func `menu open with missing data refreshes asynchronously while tracking`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        var providerRefreshCount = 0
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            refreshInteractions.append(ProviderInteractionContext.current)
            providerRefreshCount += 1
            store._setSnapshotForTesting(
                UsageSnapshot(
                    primary: RateWindow(
                        usedPercent: 25,
                        windowMinutes: 300,
                        resetsAt: Date().addingTimeInterval(3600),
                        resetDescription: nil),
                    secondary: nil,
                    updatedAt: Date()),
                provider: .codex)
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        StatusItemController.setClosedMenuPreparationDelayForTesting(.zero)
        defer { StatusItemController.resetClosedMenuPreparationDelayForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        #expect(controller.deferredMenuInteractionRefreshPending)

        for _ in 0..<40 where providerRefreshCount == 0 {
            await Task.yield()
        }

        #expect(providerRefreshCount == 1)
        #expect(refreshInteractions == [.background])
        for _ in 0..<40 where controller.deferredMenuInteractionRefreshPending {
            await Task.yield()
        }
        #expect(!controller.deferredMenuInteractionRefreshPending)
        controller.menuDidClose(menu)
        #expect(!controller.deferredMenuInteractionRefreshPending)
    }

    @Test
    func `menu open renders cached data immediately after data only invalidation`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        var providerRefreshCount = 0
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            providerRefreshCount += 1
        }
        defer { store._test_providerRefreshOverride = nil }
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }

        controller.menuRefreshEnabledOverrideForTesting = true
        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu

        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let key = ObjectIdentifier(menu)
        let cachedItemCount = menu.items.count
        let cachedVersion = controller.menuVersions[key]
        controller.lastMenuAdjunctReadinessSignature = "stale-baseline"

        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)
        let dataOnlyVersion = controller.menuContentVersion
        var asyncRebuilds = 0
        controller._test_openMenuRebuildObserver = { _ in
            asyncRebuilds += 1
        }
        defer { controller._test_openMenuRebuildObserver = nil }

        controller.menuWillOpen(menu)

        #expect(cachedVersion != dataOnlyVersion)
        #expect(menu.items.count == cachedItemCount)
        #expect(controller.menuVersions[key] == cachedVersion)
        #expect(asyncRebuilds == 0)
        #expect(!controller.deferredMenuInteractionRefreshPending)

        for _ in 0..<40 where asyncRebuilds == 0 {
            await Task.yield()
        }

        #expect(asyncRebuilds == 1)
        #expect(controller.menuVersions[key] == controller.menuContentVersion)
        #expect(!controller.didMenuAdjunctReadinessChange())
        controller.menuDidClose(menu)
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(providerRefreshCount == 0)
    }

    @Test
    func `closing before cached menu rebuild keeps next open stale`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let key = ObjectIdentifier(menu)
        let cachedVersion = controller.menuVersions[key]
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)

        var rebuildGateEntries = 0
        var rebuildGate: CheckedContinuation<Void, Never>?
        controller._test_openMenuRefreshYieldOverride = {
            rebuildGateEntries += 1
            await withCheckedContinuation { continuation in
                rebuildGate = continuation
            }
        }
        defer {
            rebuildGate?.resume()
            controller._test_openMenuRefreshYieldOverride = nil
        }

        controller.menuWillOpen(menu)
        for _ in 0..<40 where rebuildGateEntries == 0 {
            await Task.yield()
        }

        #expect(rebuildGateEntries == 1)
        #expect(controller.menuVersions[key] == cachedVersion)
        controller.menuDidClose(menu)
        #expect(controller.menuNeedsRefresh(menu))

        rebuildGate?.resume()
        rebuildGate = nil
        controller._test_openMenuRefreshYieldOverride = nil
        for _ in 0..<20 {
            await Task.yield()
        }

        controller.menuWillOpen(menu)
        for _ in 0..<40 where controller.menuNeedsRefresh(menu) {
            await Task.yield()
        }

        #expect(!controller.menuNeedsRefresh(menu))
        controller.menuDidClose(menu)
    }

    @Test
    func `menu open rebuilds synchronously after provider identity changes`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "old@example.com"),
            provider: .codex)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let cachedVersion = controller.menuVersions[ObjectIdentifier(menu)]

        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "new@example.com"),
            provider: .codex)
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.menuVersions[ObjectIdentifier(menu)] != cachedVersion)
        #expect(controller.menuVersions[ObjectIdentifier(menu)] == controller.menuContentVersion)
    }

    @Test
    func `overview menu rebuilds synchronously after secondary provider identity changes`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        settings.mergedMenuLastSelectedWasOverview = true
        self.enableProvidersForInstantOpenTesting([.codex, .claude], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "codex@example.com"),
            provider: .codex)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "old@example.com", provider: .claude),
            provider: .claude)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        controller.selectedMenuProvider = .codex

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let cachedVersion = controller.menuVersions[ObjectIdentifier(menu)]

        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "new@example.com", provider: .claude),
            provider: .claude)
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.menuVersions[ObjectIdentifier(menu)] != cachedVersion)
        #expect(controller.menuVersions[ObjectIdentifier(menu)] == controller.menuContentVersion)
    }

    @Test
    func `stacked Codex menu rebuilds synchronously after secondary account identity changes`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        settings.multiAccountMenuLayout = .stacked
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "selected@example.com"),
            provider: .codex)
        let selectedAccount = CodexVisibleAccount(
            id: "selected",
            email: "selected@example.com",
            workspaceLabel: nil,
            workspaceAccountID: nil,
            authFingerprint: nil,
            storedAccountID: nil,
            selectionSource: .liveSystem,
            isActive: true,
            isLive: true,
            canReauthenticate: false,
            canRemove: false)
        let secondaryAccount = CodexVisibleAccount(
            id: "secondary",
            email: "secondary@example.com",
            workspaceLabel: nil,
            workspaceAccountID: nil,
            authFingerprint: nil,
            storedAccountID: nil,
            selectionSource: .liveSystem,
            isActive: false,
            isLive: false,
            canReauthenticate: false,
            canRemove: false)
        store.codexAccountSnapshots = [
            CodexAccountUsageSnapshot(
                account: selectedAccount,
                snapshot: self.instantOpenSnapshot(email: "selected@example.com"),
                error: nil,
                sourceLabel: "test"),
            CodexAccountUsageSnapshot(
                account: secondaryAccount,
                snapshot: self.instantOpenSnapshot(email: "old@example.com"),
                error: nil,
                sourceLabel: "test"),
        ]
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let cachedVersion = controller.menuVersions[ObjectIdentifier(menu)]

        store.codexAccountSnapshots[1] = CodexAccountUsageSnapshot(
            account: secondaryAccount,
            snapshot: self.instantOpenSnapshot(email: "new@example.com"),
            error: nil,
            sourceLabel: "test")
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.menuVersions[ObjectIdentifier(menu)] != cachedVersion)
        #expect(controller.menuVersions[ObjectIdentifier(menu)] == controller.menuContentVersion)
    }

    @Test
    func `cache preserving structural invalidation rebuilds synchronously on open`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let key = ObjectIdentifier(menu)
        let cachedVersion = controller.menuVersions[key]

        controller.preservingMergedSwitcherContentCachesDuringInvalidation {
            controller.invalidateMenus()
        }
        #expect(controller.menuVersions[key] == cachedVersion)
        #expect(controller.menuContentVersion != controller.latestDataOnlyMenuContentVersion)

        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.menuVersions[key] == controller.menuContentVersion)
        #expect(controller.openMenuRebuildTasks[key] == nil)
    }

    @Test
    func `data invalidation after cache preserving structural invalidation still rebuilds synchronously`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        let key = ObjectIdentifier(menu)
        let cachedVersion = controller.menuVersions[key]

        controller.preservingMergedSwitcherContentCachesDuringInvalidation {
            controller.invalidateMenus()
        }
        let structuralVersion = controller.menuContentVersion
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)

        #expect(controller.menuVersions[key] == cachedVersion)
        #expect(controller.latestStructuralMenuContentVersion == structuralVersion)
        #expect(controller.menuContentVersion == controller.latestDataOnlyMenuContentVersion)

        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.menuVersions[key] == controller.menuContentVersion)
        #expect(controller.openMenuRebuildTasks[key] == nil)
    }

    @Test
    func `menu open does not overlap provider specific refresh`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
            store._setSnapshotForTesting(self.instantOpenSnapshot(email: "refreshed@example.com"), provider: .codex)
        }
        defer { store._test_providerRefreshOverride = nil }
        let existingRefreshTask = Task {
            await store.refreshProvider(.codex)
        }
        await refreshGate.waitUntilStarted(count: 1)

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }
        for _ in 0..<40 {
            await Task.yield()
        }

        #expect(await refreshGate.startCount == 1)
        #expect(store.refreshingProviders.contains(.codex))
        await refreshGate.releaseFirst()
        await existingRefreshTask.value
        for _ in 0..<40 where controller.deferredMenuInteractionRefreshPending {
            await Task.yield()
        }
        #expect(!store.isRefreshing)
        #expect(!controller.deferredMenuInteractionRefreshPending)
    }

    @Test
    func `cached menu rebuilds after active provider refresh completes`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
            store._setSnapshotForTesting(self.instantOpenSnapshot(email: "refreshed@example.com"), provider: .codex)
        }
        defer { store._test_providerRefreshOverride = nil }
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.mergedMenu = menu
        controller.statusItem.menu = menu
        controller.populateMenu(menu, provider: nil)
        controller.markMenuFresh(menu)
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)

        let existingRefreshTask = Task {
            await store.refreshProvider(.codex)
        }
        await refreshGate.waitUntilStarted(count: 1)
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }
        #expect(controller.menuNeedsRefresh(menu))

        await refreshGate.releaseFirst()
        await existingRefreshTask.value
        for _ in 0..<80 where controller.menuNeedsRefresh(menu) {
            await Task.yield()
        }

        #expect(await refreshGate.startCount == 1)
        #expect(!controller.menuNeedsRefresh(menu))
    }

    @Test
    func `menu rebuilds after displayed provider completes while another provider refreshes`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableProvidersForInstantOpenTesting([.claude, .codex], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "old@example.com"),
            provider: .codex)
        store.refreshingProviders = [.claude]
        defer { store.refreshingProviders = [] }
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu(for: .codex)
        controller.populateMenu(menu, provider: .codex)
        controller.markMenuFresh(menu)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "new@example.com"),
            provider: .codex)
        controller.invalidateMenus(allowStaleContentDuringDataRefresh: true)

        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }
        for _ in 0..<80 where controller.menuNeedsRefresh(menu) {
            await Task.yield()
        }

        #expect(!controller.menuNeedsRefresh(menu))
    }

    @Test
    func `user refresh supersedes background provider refresh`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            refreshInteractions.append(ProviderInteractionContext.current)
            await refreshGate.run()
        }
        defer { store._test_providerRefreshOverride = nil }

        let backgroundRefreshTask = Task {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.refreshProvider(.codex, coalesceIfRefreshing: true)
            }
        }
        await refreshGate.waitUntilStarted(count: 1)

        let userRefreshTask = Task {
            await ProviderInteractionContext.$current.withValue(.userInitiated) {
                await store.refresh()
            }
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(await refreshGate.startCount == 1)

        await refreshGate.releaseFirst()
        await refreshGate.waitUntilStarted(count: 2)
        await userRefreshTask.value
        await backgroundRefreshTask.value
        #expect(await refreshGate.startCount == 2)
        #expect(refreshInteractions == [.background, .userInitiated])
    }

    @Test
    func `settings refresh supersedes background provider refresh without becoming user initiated`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            refreshInteractions.append(ProviderInteractionContext.current)
            await refreshGate.run()
        }
        defer { store._test_providerRefreshOverride = nil }

        let backgroundRefreshTask = Task {
            await store.refreshProvider(.codex, coalesceIfRefreshing: true)
        }
        await refreshGate.waitUntilStarted(count: 1)

        let settingsRefreshTask = Task {
            await store.refreshForSettingsChange()
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(await refreshGate.startCount == 1)

        await refreshGate.releaseFirst()
        await refreshGate.waitUntilStarted(count: 2)
        await settingsRefreshTask.value
        await backgroundRefreshTask.value
        #expect(await refreshGate.startCount == 2)
        #expect(refreshInteractions == [.background, .background])
    }

    @Test
    func `superseded provider refresh drains before newer result`() async throws {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableProvidersForInstantOpenTesting([.claude], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshes = OrderedInstantOpenProviderRefresh()
        let baseSpec = try #require(store.providerSpecs[.claude])
        let baseDescriptor = baseSpec.descriptor
        let strategy = InstantOpenProviderFetchStrategy {
            await refreshes.awaitSnapshot()
        }
        store.providerSpecs[.claude] = ProviderSpec(
            style: baseSpec.style,
            isEnabled: baseSpec.isEnabled,
            descriptor: ProviderDescriptor(
                id: .claude,
                metadata: baseDescriptor.metadata,
                branding: baseDescriptor.branding,
                tokenCost: baseDescriptor.tokenCost,
                fetchPlan: ProviderFetchPlan(
                    sourceModes: [.auto, .cli, .oauth],
                    pipeline: ProviderFetchPipeline { _ in [strategy] }),
                cli: baseDescriptor.cli),
            makeFetchContext: baseSpec.makeFetchContext)

        let olderTask = Task {
            await store.refreshProvider(.claude)
        }
        await refreshes.waitUntilStarted(count: 1)
        let newerTask = Task {
            await store.refreshProvider(.claude)
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(await refreshes.startCount == 1)

        await refreshes.resume(
            call: 1,
            snapshot: self.instantOpenSnapshot(
                email: "old@example.com",
                provider: .claude,
                percent: 10))
        await refreshes.waitUntilStarted(count: 2)
        await refreshes.resume(
            call: 2,
            snapshot: self.instantOpenSnapshot(
                email: "new@example.com",
                provider: .claude,
                percent: 80))
        await newerTask.value
        await olderTask.value

        #expect(store.snapshot(for: .claude)?.primary?.usedPercent == 80)
        #expect(store.snapshot(for: .claude)?.accountEmail(for: .claude) == "new@example.com")
    }

    @Test
    func `superseded provider refresh cannot overwrite manually changed token`() async throws {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableProvidersForInstantOpenTesting([.stepfun], settings: settings)
        settings.stepfunToken = "initial-token"

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshes = OrderedInstantOpenProviderMutation()
        let baseSpec = try #require(store.providerSpecs[.stepfun])
        let baseDescriptor = baseSpec.descriptor
        let strategy = InstantOpenProviderMutationFetchStrategy(mutations: refreshes)
        store.providerSpecs[.stepfun] = ProviderSpec(
            style: baseSpec.style,
            isEnabled: baseSpec.isEnabled,
            descriptor: ProviderDescriptor(
                id: .stepfun,
                metadata: baseDescriptor.metadata,
                branding: baseDescriptor.branding,
                tokenCost: baseDescriptor.tokenCost,
                fetchPlan: ProviderFetchPlan(
                    sourceModes: [.auto, .web],
                    pipeline: ProviderFetchPipeline { _ in [strategy] }),
                cli: baseDescriptor.cli),
            makeFetchContext: baseSpec.makeFetchContext)

        let olderTask = Task {
            await store.refreshProvider(.stepfun)
        }
        await refreshes.waitUntilStarted(count: 1)
        let newerTask = Task {
            await store.refreshProvider(.stepfun)
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(await refreshes.startCount == 1)

        settings.stepfunToken = "user-token"
        await refreshes.resume(call: 1, token: "old-token")
        await refreshes.waitUntilStarted(count: 2)
        #expect(settings.stepfunToken == "user-token")
        await refreshes.resume(call: 2, token: "new-token")
        await newerTask.value
        await olderTask.value

        #expect(settings.stepfunToken == "new-token")
    }

    @Test
    func `superseded provider refresh preserves rotated token when credential is unchanged`() async throws {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableProvidersForInstantOpenTesting([.stepfun], settings: settings)
        settings.stepfunToken = "initial-token"

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshes = OrderedInstantOpenProviderMutation()
        let baseSpec = try #require(store.providerSpecs[.stepfun])
        let baseDescriptor = baseSpec.descriptor
        let strategy = InstantOpenProviderMutationFetchStrategy(mutations: refreshes)
        store.providerSpecs[.stepfun] = ProviderSpec(
            style: baseSpec.style,
            isEnabled: baseSpec.isEnabled,
            descriptor: ProviderDescriptor(
                id: .stepfun,
                metadata: baseDescriptor.metadata,
                branding: baseDescriptor.branding,
                tokenCost: baseDescriptor.tokenCost,
                fetchPlan: ProviderFetchPlan(
                    sourceModes: [.auto, .web],
                    pipeline: ProviderFetchPipeline { _ in [strategy] }),
                cli: baseDescriptor.cli),
            makeFetchContext: baseSpec.makeFetchContext)

        let olderTask = Task {
            await store.refreshProvider(.stepfun)
        }
        await refreshes.waitUntilStarted(count: 1)
        let newerTask = Task {
            await store.refreshProvider(.stepfun)
        }

        await refreshes.resume(call: 1, token: "rotated-token")
        await refreshes.waitUntilStarted(count: 2)
        #expect(settings.stepfunToken == "rotated-token")
        await refreshes.resume(call: 2, token: "newer-token")
        await newerTask.value
        await olderTask.value

        #expect(settings.stepfunToken == "newer-token")
    }

    @Test
    func `canceling provider refresh cancels its owned probe task`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        var refreshWasCancelled = false
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
            refreshWasCancelled = Task.isCancelled
        }
        defer { store._test_providerRefreshOverride = nil }

        let refreshTask = Task {
            await store.refreshProvider(.codex)
        }
        await refreshGate.waitUntilStarted(count: 1)
        refreshTask.cancel()
        await refreshGate.releaseFirst()
        await refreshTask.value

        #expect(refreshWasCancelled)
    }

    @Test
    func `canceling refresh owner keeps shared provider probe alive`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        var refreshWasCancelled = false
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
            refreshWasCancelled = Task.isCancelled
        }
        defer { store._test_providerRefreshOverride = nil }

        let ownerTask = Task {
            await store.refreshProvider(.codex)
        }
        await refreshGate.waitUntilStarted(count: 1)
        let sharedWaiterTask = Task {
            await store.refreshProvider(.codex, coalesceIfRefreshing: true)
        }
        for _ in 0..<40 {
            await Task.yield()
        }

        ownerTask.cancel()
        await refreshGate.releaseFirst()
        await ownerTask.value
        await sharedWaiterTask.value

        #expect(!refreshWasCancelled)
        #expect(await refreshGate.startCount == 1)
    }

    @Test
    func `background refresh retries canceled provider probe with cached data`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "cached@example.com"),
            provider: .codex)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
        }
        defer { store._test_providerRefreshOverride = nil }

        let ownerTask = Task {
            await store.refreshProvider(.codex)
        }
        await refreshGate.waitUntilStarted(count: 1)
        ownerTask.cancel()
        let backgroundTask = Task {
            await store.refreshProvider(.codex, coalesceIfRefreshing: true)
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        await refreshGate.releaseFirst()
        await ownerTask.value
        await backgroundTask.value

        #expect(await refreshGate.startCount == 2)
    }

    @Test
    func `menu open refresh only retries the displayed provider`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableProvidersForInstantOpenTesting([.claude, .codex], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        store.refreshingProviders.insert(.claude)
        defer { store.refreshingProviders.remove(.claude) }
        var refreshedProviders: [UsageProvider] = []
        store._test_providerRefreshOverride = { provider in
            refreshedProviders.append(provider)
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuProviders[ObjectIdentifier(menu)] = .codex
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }
        for _ in 0..<40 where refreshedProviders.isEmpty {
            await Task.yield()
        }

        #expect(refreshedProviders == [.codex])
    }

    @Test
    func `opening fresh split menu preserves another provider deferred retry`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableProvidersForInstantOpenTesting([.claude, .codex], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "claude@example.com", provider: .claude),
            provider: .claude)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.seconds(60))
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.seconds(60))
        defer {
            StatusItemController.resetMenuOpenRefreshDelayForTesting()
            StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting()
        }

        let codexMenu = controller.makeMenu(for: .codex)
        controller.menuWillOpen(codexMenu)
        controller.menuDidClose(codexMenu)
        #expect(controller.deferredMenuInteractionRefreshProviders == [.codex])

        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        let claudeMenu = controller.makeMenu(for: .claude)
        controller.menuWillOpen(claudeMenu)
        defer { controller.menuDidClose(claudeMenu) }
        for _ in 0..<40 {
            await Task.yield()
        }

        #expect(controller.deferredMenuInteractionRefreshProviders == [.codex])
        #expect(controller.deferredMenuInteractionRefreshPending)
    }

    @Test
    func `overview defers only providers that need retry`() {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        settings.mergedMenuLastSelectedWasOverview = true
        self.enableProvidersForInstantOpenTesting([.claude, .codex], settings: settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        store._setSnapshotForTesting(
            self.instantOpenSnapshot(email: "claude@example.com", provider: .claude),
            provider: .claude)
        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.seconds(60))
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        defer { controller.menuDidClose(menu) }

        #expect(controller.deferredMenuInteractionRefreshProviders == [.codex])
    }

    @Test
    func `closing overview menu stops before refreshing another provider`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = true
        settings.mergedMenuLastSelectedWasOverview = true
        self.enableProvidersForInstantOpenTesting([.codex, .openai], settings: settings)
        settings.updateProviderConfig(provider: .openai) { config in
            config.apiKey = "test-openai-key"
        }

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        store._setSnapshotForTesting(nil, provider: .openai)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        store._test_providerRefreshOverride = { _ in
            await refreshGate.run()
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.seconds(60))
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        await refreshGate.waitUntilStarted(count: 1)
        controller.menuDidClose(menu)
        await refreshGate.releaseFirst()
        for _ in 0..<80 {
            await Task.yield()
        }

        #expect(await refreshGate.startCount == 1)
        #expect(controller.deferredMenuInteractionRefreshPending)
    }

    @Test
    func `closing menu during missing data refresh preserves deferred retry`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        var refreshInteractions: [ProviderInteraction] = []
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            refreshInteractions.append(ProviderInteractionContext.current)
            await refreshGate.run()
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        await refreshGate.waitUntilStarted(count: 1)
        #expect(controller.deferredMenuInteractionRefreshPending)
        #expect(store.refreshingProviders.contains(.codex))

        let periodicRefreshTask = Task {
            await store.refresh()
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(await refreshGate.startCount == 1)

        controller.menuDidClose(menu)
        #expect(controller.deferredMenuInteractionRefreshPending)
        await refreshGate.releaseFirst()
        await periodicRefreshTask.value
        for _ in 0..<40 where store.isRefreshing {
            await Task.yield()
        }
        for _ in 0..<40 {
            await Task.yield()
        }
        #expect(controller.deferredMenuInteractionRefreshPending)

        controller.scheduleDeferredMenuInteractionRefreshIfNeeded(delay: .zero)
        await refreshGate.waitUntilStarted(count: 2)
        for _ in 0..<40 where controller.deferredMenuInteractionRefreshPending {
            await Task.yield()
        }

        #expect(await refreshGate.startCount == 2)
        #expect(refreshInteractions == [.background, .background])
        #expect(!controller.deferredMenuInteractionRefreshPending)
    }

    @Test
    func `closing menu during successful missing data refresh clears deferred retry`() async {
        self.disableMenuCardsForTesting()
        let settings = self.makeSettings()
        settings.statusChecksEnabled = false
        settings.refreshFrequency = .manual
        settings.mergeIcons = false
        self.enableOnlyCodexForInstantOpenTesting(settings)

        let store = self.makeCodexStore(settings: settings, dashboardAuthorized: false)
        store._setSnapshotForTesting(nil, provider: .codex)
        let refreshGate = BlockingInstantOpenProviderRefresh()
        store._test_providerRefreshOverride = { provider in
            guard provider == .codex else { return }
            await refreshGate.run()
            store._setSnapshotForTesting(
                UsageSnapshot(
                    primary: RateWindow(
                        usedPercent: 25,
                        windowMinutes: 300,
                        resetsAt: Date().addingTimeInterval(3600),
                        resetDescription: nil),
                    secondary: nil,
                    updatedAt: Date()),
                provider: .codex)
        }
        defer { store._test_providerRefreshOverride = nil }

        let controller = StatusItemController(
            store: store,
            settings: settings,
            account: UsageFetcher().loadAccountInfo(),
            updater: DisabledUpdaterController(),
            preferencesSelection: PreferencesSelection(),
            statusBar: self.makeStatusBarForTesting())
        defer { controller.releaseStatusItemsForTesting() }
        controller.menuRefreshEnabledOverrideForTesting = true
        StatusItemController.setDeferredMenuInteractionRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetDeferredMenuInteractionRefreshDelayForTesting() }
        StatusItemController.setMenuOpenRefreshDelayForTesting(.zero)
        defer { StatusItemController.resetMenuOpenRefreshDelayForTesting() }
        var deferredRefreshCount = 0
        controller.onDeferredMenuInteractionRefreshForTesting = {
            deferredRefreshCount += 1
        }

        let menu = controller.makeMenu()
        controller.menuWillOpen(menu)
        await refreshGate.waitUntilStarted(count: 1)
        controller.menuDidClose(menu)
        for _ in 0..<80 {
            await Task.yield()
        }
        #expect(deferredRefreshCount == 0)
        await refreshGate.releaseFirst()

        for _ in 0..<80 where controller.deferredMenuInteractionRefreshPending {
            await Task.yield()
        }
        for _ in 0..<40 {
            await Task.yield()
        }

        #expect(await refreshGate.startCount == 1)
        #expect(deferredRefreshCount == 0)
        #expect(!controller.deferredMenuInteractionRefreshPending)
    }

    private func enableOnlyCodexForInstantOpenTesting(_ settings: SettingsStore) {
        self.enableProvidersForInstantOpenTesting([.codex], settings: settings)
    }

    private func instantOpenSnapshot(
        email: String,
        provider: UsageProvider = .codex,
        percent: Double = 25) -> UsageSnapshot
    {
        UsageSnapshot(
            primary: RateWindow(
                usedPercent: percent,
                windowMinutes: 300,
                resetsAt: Date().addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: provider.instanceID,
                accountEmail: email,
                accountOrganization: nil,
                loginMethod: "ChatGPT"))
    }

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

private struct InstantOpenProviderFetchStrategy: ProviderFetchStrategy {
    let loader: @Sendable () async -> UsageSnapshot

    var id: String {
        "instant-open-provider-refresh-test"
    }

    var kind: ProviderFetchKind {
        .cli
    }

    func isAvailable(_: ProviderFetchContext) async -> Bool {
        true
    }

    func fetch(_: ProviderFetchContext) async throws -> ProviderFetchResult {
        let usage = await self.loader()
        return self.makeResult(usage: usage, sourceLabel: self.id)
    }

    func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
        false
    }
}

private struct InstantOpenProviderMutationFetchStrategy: ProviderFetchStrategy {
    let mutations: OrderedInstantOpenProviderMutation

    let id = "instant-open-provider-mutation-test"
    let kind: ProviderFetchKind = .web

    func isAvailable(_: ProviderFetchContext) async -> Bool {
        true
    }

    func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
        let token = await self.mutations.awaitToken()
        await context.providerManualTokenUpdater?(.stepfun, token)
        let usage = UsageSnapshot(
            primary: RateWindow(
                usedPercent: 25,
                windowMinutes: 300,
                resetsAt: Date().addingTimeInterval(3600),
                resetDescription: nil),
            secondary: nil,
            updatedAt: Date())
        return self.makeResult(usage: usage, sourceLabel: self.id)
    }

    func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
        false
    }
}

private actor OrderedInstantOpenProviderRefresh {
    private var started = 0
    private var startWaiters: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
    private var continuations: [Int: CheckedContinuation<UsageSnapshot, Never>] = [:]

    var startCount: Int {
        self.started
    }

    func awaitSnapshot() async -> UsageSnapshot {
        self.started += 1
        let call = self.started
        self.resumeReadyStartWaiters()
        return await withCheckedContinuation { continuation in
            self.continuations[call] = continuation
        }
    }

    func waitUntilStarted(count: Int) async {
        if self.started >= count { return }
        await withCheckedContinuation { continuation in
            self.startWaiters.append((count: count, continuation: continuation))
        }
    }

    func resume(call: Int, snapshot: UsageSnapshot) {
        self.continuations.removeValue(forKey: call)?.resume(returning: snapshot)
    }

    private func resumeReadyStartWaiters() {
        var remaining: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
        for waiter in self.startWaiters {
            if self.started >= waiter.count {
                waiter.continuation.resume()
            } else {
                remaining.append(waiter)
            }
        }
        self.startWaiters = remaining
    }
}

private actor OrderedInstantOpenProviderMutation {
    private var started = 0
    private var startWaiters: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
    private var continuations: [Int: CheckedContinuation<String, Never>] = [:]

    var startCount: Int {
        self.started
    }

    func awaitToken() async -> String {
        self.started += 1
        let call = self.started
        self.resumeReadyStartWaiters()
        return await withCheckedContinuation { continuation in
            self.continuations[call] = continuation
        }
    }

    func waitUntilStarted(count: Int) async {
        if self.started >= count { return }
        await withCheckedContinuation { continuation in
            self.startWaiters.append((count: count, continuation: continuation))
        }
    }

    func resume(call: Int, token: String) {
        self.continuations.removeValue(forKey: call)?.resume(returning: token)
    }

    private func resumeReadyStartWaiters() {
        var remaining: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
        for waiter in self.startWaiters {
            if self.started >= waiter.count {
                waiter.continuation.resume()
            } else {
                remaining.append(waiter)
            }
        }
        self.startWaiters = remaining
    }
}

private actor BlockingInstantOpenProviderRefresh {
    private var started = 0
    private var startWaiters: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
    private var firstReleaseWaiters: [CheckedContinuation<Void, Never>] = []
    private var firstReleased = false

    var startCount: Int {
        self.started
    }

    func run() async {
        self.started += 1
        self.resumeReadyStartWaiters()
        guard self.started == 1, !self.firstReleased else { return }
        await withCheckedContinuation { continuation in
            self.firstReleaseWaiters.append(continuation)
        }
    }

    func waitUntilStarted(count: Int) async {
        if self.started >= count { return }
        await withCheckedContinuation { continuation in
            self.startWaiters.append((count: count, continuation: continuation))
        }
    }

    func releaseFirst() {
        self.firstReleased = true
        let waiters = self.firstReleaseWaiters
        self.firstReleaseWaiters.removeAll()
        waiters.forEach { $0.resume() }
    }

    private func resumeReadyStartWaiters() {
        var remaining: [(count: Int, continuation: CheckedContinuation<Void, Never>)] = []
        for waiter in self.startWaiters {
            if self.started >= waiter.count {
                waiter.continuation.resume()
            } else {
                remaining.append(waiter)
            }
        }
        self.startWaiters = remaining
    }
}
