import CodexBarCore
import Foundation
import Testing
@testable import CodexBar

struct UsageStorePlanUtilizationClaudeIdentityTests {
    @MainActor
    @Test
    func `selected token account chooses matching bucket`() throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        store.settings.addTokenAccount(provider: .claude, label: "Alice", token: "alice-token")
        store.settings.addTokenAccount(provider: .claude, label: "Bob", token: "bob-token")
        let accounts = store.settings.tokenAccounts(for: .claude)
        let alice = try #require(accounts.first)
        let bob = try #require(accounts.last)
        let aliceKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: alice))
        let bobKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: bob))

        store.settings.setActiveTokenAccountIndex(0, for: .claude)
        store.planUtilizationHistory[.claude] = PlanUtilizationHistoryBuckets(accounts: [
            aliceKey: [planSeries(name: .weekly, windowMinutes: 10080, entries: [
                planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 20),
            ])],
            bobKey: [planSeries(name: .weekly, windowMinutes: 10080, entries: [
                planEntry(at: Date(timeIntervalSince1970: 1_700_086_400), usedPercent: 50),
            ])],
        ])

        #expect(store.planUtilizationHistory(for: .claude) == [
            planSeries(name: .weekly, windowMinutes: 10080, entries: [
                planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 20),
            ]),
        ])

        store.settings.setActiveTokenAccountIndex(1, for: .claude)
        #expect(store.planUtilizationHistory(for: .claude) == [
            planSeries(name: .weekly, windowMinutes: 10080, entries: [
                planEntry(at: Date(timeIntervalSince1970: 1_700_086_400), usedPercent: 50),
            ]),
        ])
    }

    @MainActor
    @Test
    func `fetched non selected accounts persist into separate claude buckets`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        store.settings.addTokenAccount(provider: .claude, label: "Alice", token: "alice-token")
        store.settings.addTokenAccount(provider: .claude, label: "Bob", token: "bob-token")
        let accounts = store.settings.tokenAccounts(for: .claude)
        let alice = try #require(accounts.first)
        let bob = try #require(accounts.last)
        let bobKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: bob))

        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 20, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
            tertiary: RateWindow(usedPercent: 30, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "bob@example.com",
                accountOrganization: nil,
                loginMethod: "max"))

        await store.recordFetchedTokenAccountPlanUtilizationHistory(
            provider: .claude,
            samples: [(account: bob, snapshot: snapshot)],
            selectedAccount: alice)

        let buckets = try #require(store.planUtilizationHistory[.claude])
        let histories = try #require(buckets.accounts[bobKey])
        #expect(findSeries(histories, name: .session, windowMinutes: 300)?.entries.last?.usedPercent == 10)
        #expect(findSeries(histories, name: .weekly, windowMinutes: 10080)?.entries.last?.usedPercent == 20)
        #expect(findSeries(histories, name: .opus, windowMinutes: 10080)?.entries.last?.usedPercent == 30)
    }

    @MainActor
    @Test
    func `first resolved claude token account adopts unscoped history`() throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        store.settings.addTokenAccount(provider: .claude, label: "Alice", token: "alice-token")
        let alice = try #require(store.settings.tokenAccounts(for: .claude).first)
        let aliceKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: alice))
        let bootstrap = planSeries(name: .session, windowMinutes: 300, entries: [
            planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 15),
        ])
        store.planUtilizationHistory[.claude] = PlanUtilizationHistoryBuckets(unscoped: [bootstrap])
        store.settings.setActiveTokenAccountIndex(0, for: .claude)

        let history = store.planUtilizationHistory(for: .claude)
        let buckets = try #require(store.planUtilizationHistory[.claude])

        #expect(history == [bootstrap])
        #expect(buckets.unscoped.isEmpty)
        #expect(buckets.accounts[aliceKey] == [bootstrap])
    }

    @MainActor
    @Test
    func `claude oauth credential owner separates switched account history`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let accountBOwner = self.oauthOwnerIdentifier("b")
        let accountASnapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 10, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 20, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "alice@example.com",
                accountOrganization: nil,
                loginMethod: "max"))
        let accountAKey = try #require(
            UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: accountASnapshot))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: accountASnapshot,
            now: Date(timeIntervalSince1970: 1_700_000_000))

        let accountBSnapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 70, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: RateWindow(usedPercent: 80, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
            updatedAt: Date())
        let accountBKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: accountBOwner))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: accountBSnapshot,
            claudeOAuthPersistentRefHash: "account-b-ref",
            claudeOAuthHistoryOwnerIdentifier: accountBOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_007_200))
        store._setSnapshotForTesting(accountBSnapshot, provider: .claude)

        let selectedHistory = store.planUtilizationHistory(for: .claude)
        let buckets = try #require(store.planUtilizationHistory[.claude])
        let accountAHistory = try #require(buckets.accounts[accountAKey])
        let accountBHistory = try #require(buckets.accounts[accountBKey])

        #expect(buckets.preferredAccountKey == accountBKey)
        #expect(buckets.unscoped.isEmpty)
        #expect(findSeries(accountAHistory, name: .session, windowMinutes: 300)?.entries.last?.usedPercent == 10)
        #expect(findSeries(accountAHistory, name: .weekly, windowMinutes: 10080)?.entries.last?.usedPercent == 20)
        #expect(findSeries(accountBHistory, name: .session, windowMinutes: 300)?.entries.last?.usedPercent == 70)
        #expect(findSeries(accountBHistory, name: .weekly, windowMinutes: 10080)?.entries.last?.usedPercent == 80)
        #expect(findSeries(selectedHistory, name: .session, windowMinutes: 300)?.entries.last?.usedPercent == 70)
    }

    @MainActor
    @Test
    func `claude oauth credential owner wins over configured token account`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let oauthOwner = self.oauthOwnerIdentifier("a")
        store.settings.addTokenAccount(provider: .claude, label: "Unrelated", token: "unrelated-token")
        store.settings.setActiveTokenAccountIndex(0, for: .claude)
        let selectedAccount = try #require(store.settings.selectedTokenAccount(for: .claude))
        let tokenAccountKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: selectedAccount))
        let oauthAccountKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: oauthOwner))
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 45, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            updatedAt: Date())

        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: snapshot,
            claudeOAuthPersistentRefHash: "oauth-ref",
            claudeOAuthHistoryOwnerIdentifier: oauthOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_000_000))
        store._setSnapshotForTesting(snapshot, provider: .claude)

        let selection = store.planUtilizationHistorySelection(for: .claude)
        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(buckets.preferredAccountKey == oauthAccountKey)
        #expect(buckets.accounts[tokenAccountKey] == nil)
        #expect(findSeries(buckets.accounts[oauthAccountKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [45])
        #expect(selection.accountKey == oauthAccountKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [45])
    }

    @MainActor
    @Test
    func `claude oauth without credential ownership is not persisted`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        store.settings.addTokenAccount(provider: .claude, label: "Unrelated", token: "unrelated-token")
        store.settings.setActiveTokenAccountIndex(0, for: .claude)
        let selectedAccount = try #require(store.settings.selectedTokenAccount(for: .claude))
        let tokenAccountKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: selectedAccount))
        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 55, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            updatedAt: Date())

        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: snapshot,
            claudeOAuthPersistentRefHash: "row-only-ref",
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_000_000))
        store._setSnapshotForTesting(snapshot, provider: .claude)

        let selection = store.planUtilizationHistorySelection(for: .claude)
        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(buckets.unscoped.isEmpty)
        #expect(buckets.accounts.isEmpty)
        #expect(selection.accountKey == tokenAccountKey)
        #expect(selection.histories.isEmpty)
    }

    @MainActor
    @Test
    func `coalesced claude oauth sample still switches preferred account`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let accountAOwner = self.oauthOwnerIdentifier("a")
        let accountBOwner = self.oauthOwnerIdentifier("b")
        let accountAKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: accountAOwner))
        let accountBKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: accountBOwner))
        let hourStart = Date(timeIntervalSince1970: 1_700_000_000)

        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 70),
            claudeOAuthPersistentRefHash: "account-a-ref",
            claudeOAuthHistoryOwnerIdentifier: accountAOwner,
            isClaudeOAuthSample: true,
            now: hourStart)
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 40),
            claudeOAuthPersistentRefHash: "account-b-ref",
            claudeOAuthHistoryOwnerIdentifier: accountBOwner,
            isClaudeOAuthSample: true,
            now: hourStart.addingTimeInterval(5 * 60))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 60),
            claudeOAuthPersistentRefHash: "account-a-ref",
            claudeOAuthHistoryOwnerIdentifier: accountAOwner,
            isClaudeOAuthSample: true,
            now: hourStart.addingTimeInterval(10 * 60))

        let buckets = try #require(store.planUtilizationHistory[.claude])
        let selection = store.planUtilizationHistorySelection(for: .claude)
        #expect(buckets.preferredAccountKey == accountAKey)
        #expect(findSeries(buckets.accounts[accountAKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [70])
        #expect(findSeries(buckets.accounts[accountBKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [40])
        #expect(selection.accountKey == accountAKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [70])
    }

    @MainActor
    @Test
    func `same dir account switch quarantines stale background credential`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let ownerA = self.oauthOwnerIdentifier("a")
        let ownerB = self.oauthOwnerIdentifier("b")
        let keyA = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(historyOwnerIdentifier: ownerA))
        let keyB = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(historyOwnerIdentifier: ownerB))
        let hourStart = Date(timeIntervalSince1970: 1_700_000_000)

        // 1) Active account A (~/.claude.json = uuid-A). Two stable exact-Keychain observations bind owner_A
        //    to A; the short confirmation interval does not add a second history point.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-A") {
            await ProviderInteractionContext.$current.withValue(.userInitiated) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 30),
                    claudeOAuthPersistentRefHash: "account-a-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-A")),
                    isClaudeOAuthSample: true,
                    now: hourStart)
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 30),
                    claudeOAuthPersistentRefHash: "account-a-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-A")),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(30 * 60))
            }
        }

        do {
            let buckets = try #require(store.planUtilizationHistory[.claude])
            #expect(findSeries(buckets.accounts[keyA] ?? [], name: .session, windowMinutes: 300)?
                .entries.map(\.usedPercent) == [30])
            #expect(buckets.unscoped.isEmpty)
        }

        // 2) `/login` switched the active account to B (~/.claude.json = uuid-B), but the gated BACKGROUND
        //    poll still serves the STALE owner_A credential. Prompt-free Keychain comparison is unavailable,
        //    but the existing owner_A -> uuid-A binding detects the mismatch, so this must be quarantined:
        //    no new sample lands.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-B") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 90),
                    claudeOAuthPersistentRefHash: nil,
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthKeychainCredentialUnavailable: true,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-B")),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(2 * 60 * 60))
            }
        }

        do {
            let buckets = try #require(store.planUtilizationHistory[.claude])
            // key_A history is UNCHANGED (the stale sample was dropped, not appended).
            #expect(findSeries(buckets.accounts[keyA] ?? [], name: .session, windowMinutes: 300)?
                .entries.map(\.usedPercent) == [30])
            // Critically, the quarantined sample did NOT leak into the shared unscoped bucket. This is the
            // assertion that catches the naive-nil bug (nil accountKey writes to `unscoped`, not nowhere).
            #expect(buckets.unscoped.isEmpty)
            #expect(buckets.accounts[keyB] == nil)
        }

        // 3) A USER-INITIATED refresh yields account B's real credential (owner_B), with exact current-Keychain
        //    match evidence. Recovery: bind owner_B -> uuid-B, write to key_B, and leave key_A untouched.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-B") {
            await ProviderInteractionContext.$current.withValue(.userInitiated) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 75),
                    claudeOAuthPersistentRefHash: "account-b-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerB,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-B")),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(3 * 60 * 60))
            }
        }

        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(findSeries(buckets.accounts[keyB] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [75])
        #expect(findSeries(buckets.accounts[keyA] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [30])
        #expect(buckets.unscoped.isEmpty)
    }

    @MainActor
    @Test
    func `exact keychain match arms account map on background poll`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let ownerA = self.oauthOwnerIdentifier("a")
        let ownerB = self.oauthOwnerIdentifier("b")
        let keyA = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(historyOwnerIdentifier: ownerA))
        let keyB = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(historyOwnerIdentifier: ownerB))
        let hourStart = Date(timeIntervalSince1970: 1_700_000_000)

        // 1) First run after upgrading: the map is empty. A background poll serves owner_A while
        //    ~/.claude.json reports uuid-A, and exact current-Keychain evidence corroborates the credential.
        //    The first observation stages a candidate; a later identical observation confirms the binding.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-A") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 30),
                    claudeOAuthPersistentRefHash: "account-a-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-A")),
                    isClaudeOAuthSample: true,
                    now: hourStart)
            }
        }

        let accountAIdentity = UsageStore._activeClaudeAccountIdentityForTesting("uuid-A")
        let accountBIdentity = UsageStore._activeClaudeAccountIdentityForTesting("uuid-B")
        #expect(UsageStore.loadClaudeOAuthAccountUuidMap(from: store.settings.userDefaults)[ownerA] == nil)
        #expect(UsageStore.loadClaudeOAuthAccountBindingCandidateMap(
            from: store.settings.userDefaults)[ownerA]?.identity == accountAIdentity)

        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-A") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 30),
                    claudeOAuthPersistentRefHash: "account-a-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthActiveAccountObservation: .stable(identity: accountAIdentity),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(30 * 60))
            }
        }
        #expect(UsageStore.loadClaudeOAuthAccountUuidMap(
            from: store.settings.userDefaults)[ownerA] == accountAIdentity)

        // 2) `/login` switched to account B (~/.claude.json = uuid-B), but the gated BACKGROUND poll still
        //    serves the stale owner_A credential. It no longer matches the current Keychain item, and the
        //    existing owner_A -> uuid-A binding detects the UUID mismatch, so the sample is quarantined.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-B") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 90),
                    claudeOAuthPersistentRefHash: nil,
                    claudeOAuthHistoryOwnerIdentifier: ownerA,
                    claudeOAuthKeychainCredentialMismatch: true,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-B")),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(2 * 60 * 60))
            }
        }

        do {
            let mapAfterBackground = UsageStore.loadClaudeOAuthAccountUuidMap(from: store.settings.userDefaults)
            #expect(mapAfterBackground[ownerA] == accountAIdentity)
            let buckets = try #require(store.planUtilizationHistory[.claude])
            #expect(findSeries(buckets.accounts[keyA] ?? [], name: .session, windowMinutes: 300)?
                .entries.map(\.usedPercent) == [30])
            #expect(buckets.unscoped.isEmpty)
        }

        // 3) A background poll now yields account B's real credential (owner_B) with exact current-Keychain
        //    match evidence. That evidence, not the interaction label, binds owner_B -> uuid-B and writes key_B.
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-B") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 75),
                    claudeOAuthPersistentRefHash: "account-b-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerB,
                    claudeOAuthActiveAccountObservation: .stable(
                        identity: UsageStore._activeClaudeAccountIdentityForTesting("uuid-B")),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(3 * 60 * 60))
            }
        }

        #expect(UsageStore.loadClaudeOAuthAccountUuidMap(from: store.settings.userDefaults)[ownerB] == nil)
        await UsageStore.withActiveClaudeAccountUuidForTesting("uuid-B") {
            await ProviderInteractionContext.$current.withValue(.background) {
                await store.recordPlanUtilizationHistorySample(
                    provider: .claude,
                    snapshot: self.identitylessClaudeSnapshot(usedPercent: 75),
                    claudeOAuthPersistentRefHash: "account-b-ref",
                    claudeOAuthHistoryOwnerIdentifier: ownerB,
                    claudeOAuthActiveAccountObservation: .stable(identity: accountBIdentity),
                    isClaudeOAuthSample: true,
                    now: hourStart.addingTimeInterval(3 * 60 * 60 + 30 * 60))
            }
        }

        let mapAfterRecovery = UsageStore.loadClaudeOAuthAccountUuidMap(from: store.settings.userDefaults)
        #expect(mapAfterRecovery[ownerB] == accountBIdentity)
        #expect(mapAfterRecovery[ownerA] == accountAIdentity)
        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(findSeries(buckets.accounts[keyB] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [75])
        #expect(buckets.unscoped.isEmpty)
    }

    @MainActor
    @Test
    func `coalesced claude oauth sample without owner cannot switch preferred account`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let scopedOwner = self.oauthOwnerIdentifier("c")
        let scopedAccountKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: scopedOwner))
        let hourStart = Date(timeIntervalSince1970: 1_700_000_000)

        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 70),
            isClaudeOAuthSample: true,
            now: hourStart)
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 40),
            claudeOAuthPersistentRefHash: "scoped-ref",
            claudeOAuthHistoryOwnerIdentifier: scopedOwner,
            isClaudeOAuthSample: true,
            now: hourStart.addingTimeInterval(5 * 60))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 60),
            isClaudeOAuthSample: true,
            now: hourStart.addingTimeInterval(10 * 60))

        let buckets = try #require(store.planUtilizationHistory[.claude])
        let selection = store.planUtilizationHistorySelection(for: .claude)
        #expect(buckets.preferredAccountKey == scopedAccountKey)
        #expect(buckets.unscoped.isEmpty)
        #expect(findSeries(buckets.accounts[scopedAccountKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [40])
        #expect(selection.accountKey == scopedAccountKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [40])
    }

    @MainActor
    @Test
    func `reloaded scoped claude oauth preference wins over configured token account`() throws {
        let oauthOwner = self.oauthOwnerIdentifier("a")
        let oauthAccountKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: oauthOwner))
        let oauthHistory = planSeries(name: .session, windowMinutes: 300, entries: [
            planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 45),
        ])
        let store = self.makeReloadedStoreWithConfiguredTokenAccount(
            buckets: PlanUtilizationHistoryBuckets(
                preferredAccountKey: oauthAccountKey,
                accounts: [oauthAccountKey: [oauthHistory]]))

        #expect(store.lastSourceLabels[.claude] == nil)
        #expect(store.settings.selectedTokenAccount(for: .claude) != nil)

        let selection = store.planUtilizationHistorySelection(for: .claude)

        #expect(selection.accountKey == oauthAccountKey)
        #expect(selection.histories == [oauthHistory])
        #expect(store.planUtilizationHistory[.claude]?.preferredAccountKey == oauthAccountKey)
    }

    @MainActor
    @Test
    func `reloaded unscoped claude oauth preference wins over configured token account`() {
        let oauthHistory = planSeries(name: .session, windowMinutes: 300, entries: [
            planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 55),
        ])
        let store = self.makeReloadedStoreWithConfiguredTokenAccount(
            buckets: PlanUtilizationHistoryBuckets(
                preferredAccountKey: "__unscoped__",
                unscoped: [oauthHistory]))

        #expect(store.lastSourceLabels[.claude] == nil)
        #expect(store.settings.selectedTokenAccount(for: .claude) != nil)

        let selection = store.planUtilizationHistorySelection(for: .claude)

        #expect(selection.accountKey == nil)
        #expect(selection.histories == [oauthHistory])
        #expect(store.planUtilizationHistory[.claude]?.preferredAccountKey == "__unscoped__")
    }

    @MainActor
    @Test
    func `later token account sample supersedes claude oauth preference`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let oauthOwner = self.oauthOwnerIdentifier("a")
        store.settings.addTokenAccount(provider: .claude, label: "Selected", token: "selected-token")
        store.settings.setActiveTokenAccountIndex(0, for: .claude)
        let selectedAccount = try #require(store.settings.selectedTokenAccount(for: .claude))
        let tokenAccountKey = try #require(
            UsageStore._planUtilizationTokenAccountKeyForTesting(provider: .claude, account: selectedAccount))
        let oauthAccountKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: oauthOwner))
        let oauthSnapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 45, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            updatedAt: Date())
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: oauthSnapshot,
            claudeOAuthPersistentRefHash: "oauth-ref",
            claudeOAuthHistoryOwnerIdentifier: oauthOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_000_000))

        let tokenSnapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 20, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            updatedAt: Date())
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: tokenSnapshot,
            account: selectedAccount,
            now: Date(timeIntervalSince1970: 1_700_007_200))

        let buckets = try #require(store.planUtilizationHistory[.claude])
        let selection = store.planUtilizationHistorySelection(for: .claude)
        #expect(buckets.preferredAccountKey == tokenAccountKey)
        #expect(findSeries(buckets.accounts[oauthAccountKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [45])
        #expect(selection.accountKey == tokenAccountKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [20])
    }

    @MainActor
    @Test
    func `first claude oauth owner quarantines legacy unscoped history`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let currentOwner = self.oauthOwnerIdentifier("c")
        let legacy = planSeries(name: .session, windowMinutes: 300, entries: [
            planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 25),
        ])
        store.planUtilizationHistory[.claude] = PlanUtilizationHistoryBuckets(unscoped: [legacy])

        let snapshot = UsageSnapshot(
            primary: RateWindow(usedPercent: 60, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
            secondary: nil,
            updatedAt: Date())
        let accountKey = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: currentOwner))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: snapshot,
            claudeOAuthPersistentRefHash: "current-ref",
            claudeOAuthHistoryOwnerIdentifier: currentOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_007_200))

        let buckets = try #require(store.planUtilizationHistory[.claude])
        let scoped = try #require(buckets.accounts[accountKey])
        #expect(buckets.unscoped == [legacy])
        #expect(findSeries(scoped, name: .session, windowMinutes: 300)?.entries.map(\.usedPercent) == [60])
        #expect(buckets.preferredAccountKey == accountKey)
    }

    @MainActor
    @Test
    func `provenance-less claude oauth credentials stay isolated across restart`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let accountAOwner = self.oauthOwnerIdentifier("a")
        let accountBOwner = self.oauthOwnerIdentifier("b")
        let accountAKey = try #require(UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
            historyOwnerIdentifier: accountAOwner))
        let accountBKey = try #require(UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
            historyOwnerIdentifier: accountBOwner))

        await UsageStore.withActiveClaudeAccountUuidForTesting(nil) {
            await store.recordPlanUtilizationHistorySample(
                provider: .claude,
                snapshot: self.identitylessClaudeSnapshot(usedPercent: 10),
                claudeOAuthHistoryOwnerIdentifier: accountAOwner,
                isClaudeOAuthSample: true,
                now: Date(timeIntervalSince1970: 1_700_000_000))
            await store.recordPlanUtilizationHistorySample(
                provider: .claude,
                snapshot: self.identitylessClaudeSnapshot(usedPercent: 75),
                claudeOAuthHistoryOwnerIdentifier: accountBOwner,
                isClaudeOAuthSample: true,
                now: Date(timeIntervalSince1970: 1_700_007_200))
        }

        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(buckets.unscoped.isEmpty)
        #expect(findSeries(buckets.accounts[accountAKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [10])
        #expect(findSeries(buckets.accounts[accountBKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [75])

        let reloaded = self.makeReloadedStoreWithConfiguredTokenAccount(buckets: buckets)
        let selection = reloaded.planUtilizationHistorySelection(for: .claude)
        #expect(selection.accountKey == accountBKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [75])
        #expect(reloaded.planUtilizationHistory[.claude]?.accounts[accountAKey] != nil)
    }

    @MainActor
    @Test
    func `same keychain reference credential replacement stays isolated across restart`() async throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let originalOwner = self.oauthOwnerIdentifier("c")
        let replacementOwner = self.oauthOwnerIdentifier("d")
        let originalKey = try #require(UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
            historyOwnerIdentifier: originalOwner,
            persistentRefHash: "same-row-ref"))
        let replacementKey = try #require(UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
            historyOwnerIdentifier: replacementOwner,
            persistentRefHash: "same-row-ref"))

        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 25),
            claudeOAuthPersistentRefHash: "same-row-ref",
            claudeOAuthHistoryOwnerIdentifier: originalOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_000_000))
        await store.recordPlanUtilizationHistorySample(
            provider: .claude,
            snapshot: self.identitylessClaudeSnapshot(usedPercent: 80),
            claudeOAuthPersistentRefHash: "same-row-ref",
            claudeOAuthHistoryOwnerIdentifier: replacementOwner,
            isClaudeOAuthSample: true,
            now: Date(timeIntervalSince1970: 1_700_007_200))

        let buckets = try #require(store.planUtilizationHistory[.claude])
        #expect(originalKey != replacementKey)
        #expect(findSeries(buckets.accounts[originalKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [25])
        #expect(findSeries(buckets.accounts[replacementKey] ?? [], name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [80])

        let reloaded = self.makeReloadedStoreWithConfiguredTokenAccount(buckets: buckets)
        let selection = reloaded.planUtilizationHistorySelection(for: .claude)
        #expect(selection.accountKey == replacementKey)
        #expect(findSeries(selection.histories, name: .session, windowMinutes: 300)?
            .entries.map(\.usedPercent) == [80])
        #expect(reloaded.planUtilizationHistory[.claude]?.accounts[originalKey] != nil)
    }

    @Test
    func `claude oauth history key is stable for one credential owner`() throws {
        let owner = self.oauthOwnerIdentifier("a")
        let first = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(historyOwnerIdentifier: owner))
        let refreshed = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: " \(owner.uppercased()) "))
        let switched = try #require(
            UsageStore._claudeOAuthPlanUtilizationAccountKeyForTesting(
                historyOwnerIdentifier: self.oauthOwnerIdentifier("b")))

        #expect(first == refreshed)
        #expect(first != switched)
        #expect(first != owner)
        #expect(first.hasPrefix("__claude_oauth__:"))
        #expect(first.dropFirst("__claude_oauth__:".count).count == 64)
    }

    @Test
    func `same claude email separates team and personal plan history keys`() throws {
        let team = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: "Team Org",
                loginMethod: "Claude Team"))
        let max = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: nil,
                loginMethod: "Claude Max"))

        let teamKey = try #require(UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: team))
        let maxKey = try #require(UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: max))

        #expect(teamKey != maxKey)
    }

    @Test
    func `claude email only identity keeps legacy history key`() throws {
        let snapshot = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: nil,
                loginMethod: nil))

        let identityKey = try #require(
            UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: snapshot))
        let legacyKey = try #require(
            UsageStore._legacyClaudePlanUtilizationEmailAccountKeyForTesting(snapshot: snapshot))

        #expect(identityKey == legacyKey)
    }

    @Test
    func `claude compact and branded plan labels share history key`() throws {
        let compact = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: nil,
                loginMethod: "Max"))
        let branded = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: nil,
                loginMethod: "Claude Max"))

        let compactKey = try #require(
            UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: compact))
        let brandedKey = try #require(
            UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: branded))

        #expect(compactKey == brandedKey)
    }

    @MainActor
    @Test
    func `new claude email discriminator adopts legacy email history`() throws {
        let store = UsageStorePlanUtilizationTests.makeStore()
        let snapshot = UsageSnapshot(
            primary: nil,
            secondary: nil,
            updatedAt: Date(),
            identity: ProviderIdentitySnapshot(
                providerID: .claude,
                accountEmail: "person@example.com",
                accountOrganization: "Team Org",
                loginMethod: "Claude Team"))
        let legacyKey = try #require(
            UsageStore._legacyClaudePlanUtilizationEmailAccountKeyForTesting(snapshot: snapshot))
        let accountKey = try #require(
            UsageStore._planUtilizationAccountKeyForTesting(provider: .claude, snapshot: snapshot))
        let legacyWeekly = planSeries(name: .weekly, windowMinutes: 10080, entries: [
            planEntry(at: Date(timeIntervalSince1970: 1_700_000_000), usedPercent: 42),
        ])
        store.planUtilizationHistory[.claude] = PlanUtilizationHistoryBuckets(
            preferredAccountKey: legacyKey,
            accounts: [
                legacyKey: [legacyWeekly],
            ])
        store._setSnapshotForTesting(snapshot, provider: .claude)

        let history = store.planUtilizationHistory(for: .claude)
        let buckets = try #require(store.planUtilizationHistory[.claude])

        #expect(history == [legacyWeekly])
        #expect(buckets.accounts[legacyKey] == nil)
        #expect(buckets.accounts[accountKey] == [legacyWeekly])
        #expect(buckets.preferredAccountKey == accountKey)
    }

    private func oauthOwnerIdentifier(_ character: Character) -> String {
        String(repeating: String(character), count: 64)
    }

    private func identitylessClaudeSnapshot(usedPercent: Double) -> UsageSnapshot {
        UsageSnapshot(
            primary: RateWindow(
                usedPercent: usedPercent,
                windowMinutes: 300,
                resetsAt: nil,
                resetDescription: nil),
            secondary: nil,
            updatedAt: Date())
    }

    @MainActor
    private func makeReloadedStoreWithConfiguredTokenAccount(
        buckets: PlanUtilizationHistoryBuckets) -> UsageStore
    {
        let suiteName = "UsageStorePlanUtilizationClaudeReload-\(UUID().uuidString)"
        guard let defaults = UserDefaults(suiteName: suiteName) else {
            fatalError("Failed to create isolated UserDefaults suite for tests")
        }
        defaults.removePersistentDomain(forName: suiteName)
        let historyStore = testPlanUtilizationHistoryStore(suiteName: suiteName)
        historyStore.save([.claude: buckets])
        let settings = SettingsStore(
            userDefaults: defaults,
            configStore: testConfigStore(suiteName: suiteName),
            tokenAccountStore: InMemoryTokenAccountStore())
        settings.addTokenAccount(provider: .claude, label: "Unrelated", token: "unrelated-token")
        settings.setActiveTokenAccountIndex(0, for: .claude)
        let store = UsageStore(
            fetcher: UsageFetcher(),
            browserDetection: BrowserDetection(cacheTTL: 0),
            settings: settings,
            planUtilizationHistoryStore: historyStore,
            startupBehavior: .testing)
        // Cancel the background decode and apply the disk-loaded buckets
        // synchronously so callers can immediately query without racing the
        // utility-priority load task.
        store._cancelPlanUtilizationHistoryLoadForTesting()
        store.planUtilizationHistory = store.planUtilizationHistoryStore.load()
        return store
    }
}
