import CodexBarCore
import Foundation

enum CodexAccountScopedRefreshPhase {
    case invalidated
    case usage
    case credits
    case dashboard
    case completed
}

struct CodexAccountScopedRefreshGuard: Equatable {
    let source: CodexActiveSource
    let identity: CodexIdentity
    let accountKey: String?
    let authFingerprint: String?

    init(
        source: CodexActiveSource,
        identity: CodexIdentity,
        accountKey: String?,
        authFingerprint: String? = nil)
    {
        self.source = source
        self.identity = identity
        self.accountKey = CodexIdentityResolver.normalizeEmail(accountKey)
        self.authFingerprint = CodexAuthFingerprint.normalize(authFingerprint)
    }
}

@MainActor
extension UsageStore {
    func refreshCodexAccountScopedState(
        allowDisabled: Bool = false,
        phaseDidChange: (@MainActor (CodexAccountScopedRefreshPhase) -> Void)? = nil)
        async
    {
        let refreshStartedAt = Date()
        self.prepareRefreshState(for: .codex)
        if self.prepareCodexAccountScopedRefreshIfNeeded() {
            phaseDidChange?(.invalidated)
        }

        await self.refreshProvider(.codex, allowDisabled: allowDisabled)
        phaseDidChange?(.usage)
        await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)
        phaseDidChange?(.credits)

        if self.settings.codexCookieSource.isEnabled {
            let expectedGuard = self.freshCodexOpenAIWebRefreshGuard()
            await self.refreshOpenAIDashboardIfNeeded(
                force: true,
                expectedGuard: expectedGuard,
                bypassCoalescing: true,
                allowCodexUsageBackfill: true)
            phaseDidChange?(.dashboard)
        }

        if self.openAIDashboardRequiresLogin {
            await self.refreshProvider(.codex, allowDisabled: allowDisabled)
            phaseDidChange?(.usage)
            await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)
            phaseDidChange?(.credits)
        }

        self.persistWidgetSnapshot(reason: "codex-account-refresh")
        phaseDidChange?(.completed)
    }

    @discardableResult
    func prepareCodexAccountScopedRefreshIfNeeded(
        forceInvalidation: Bool = false,
        currentGuardOverride: CodexAccountScopedRefreshGuard? = nil) -> Bool
    {
        let currentGuard = currentGuardOverride ?? self.freshCodexAccountScopedRefreshGuard(
            preferCurrentSnapshot: false,
            allowLastKnownLiveFallback: false)
        let previousGuard = self.lastCodexAccountScopedRefreshGuard
        self.lastCodexAccountScopedRefreshGuard = currentGuard

        let accountChanged = previousGuard.map {
            !Self.codexScopedRefreshGuardsMatchAccount($0, currentGuard)
        } ?? false
        guard forceInvalidation || accountChanged else { return false }

        let preserveSessionQuotaTransitionState = !forceInvalidation &&
            Self.codexSessionQuotaOwnersMatch(previousGuard, currentGuard)
        self.clearCodexPublishedUsageState(
            preserveSessionQuotaTransitionState: preserveSessionQuotaTransitionState)

        self.credits = nil
        self.lastCreditsError = nil
        self.lastCreditsSnapshot = nil
        self.lastCreditsSnapshotAccountKey = nil
        self.lastCreditsSource = .none
        self.creditsFailureStreak = 0

        self.clearCodexOpenAIWebStateForAccountTransition(targetEmail: self.codexAccountEmailForOpenAIDashboard())

        self.persistWidgetSnapshot(reason: "codex-account-invalidate")
        return true
    }

    func clearCodexPublishedUsageState(preserveSessionQuotaTransitionState: Bool = false) {
        self.snapshots.removeValue(forKey: .codex)
        self.errors[.codex] = nil
        self.lastSourceLabels.removeValue(forKey: .codex)
        self.lastFetchAttempts.removeValue(forKey: .codex)
        self.accountSnapshots.removeValue(forKey: .codex)
        // Visible-account rows carry their own owner and are reconciled against the current projection.
        // Clearing selected-account state must not discard valid sibling rows.
        self.failureGates[.codex]?.reset()
        if !preserveSessionQuotaTransitionState {
            self.requireFreshCodexSessionQuotaBaseline()
        }
        self.lastKnownResetSnapshots.removeValue(forKey: .codex)
        self.lastCodexUsagePublicationGuard = nil
    }

    @discardableResult
    func reconcileCodexPublishedUsageOwner(
        with currentGuard: CodexAccountScopedRefreshGuard,
        persistWidgetSnapshot: Bool = true) -> Bool
    {
        let hasPublishedUsageState = self.snapshots[.codex] != nil ||
            self.lastKnownResetSnapshots[.codex] != nil ||
            self.errors[.codex] != nil ||
            self.lastSourceLabels[.codex] != nil ||
            self.lastFetchAttempts[.codex] != nil
        guard hasPublishedUsageState else { return false }
        guard self.lastCodexUsagePublicationGuard.map({
            Self.codexScopedRefreshGuardsMatchAccount($0, currentGuard)
        }) == true
        else {
            let preserveSessionQuotaTransitionState = Self.codexSessionQuotaOwnersMatch(
                self.lastCodexUsagePublicationGuard,
                currentGuard)
            self.clearCodexPublishedUsageState(
                preserveSessionQuotaTransitionState: preserveSessionQuotaTransitionState)
            if persistWidgetSnapshot {
                self.persistWidgetSnapshot(reason: "codex-account-invalidate")
            }
            return true
        }
        return false
    }

    func reconcileCodexAccountStateForUsageOwner(_ currentGuard: CodexAccountScopedRefreshGuard) {
        let clearedUsage = self.reconcileCodexPublishedUsageOwner(
            with: currentGuard,
            persistWidgetSnapshot: false)
        let invalidatedAccountState = self.prepareCodexAccountScopedRefreshIfNeeded(
            currentGuardOverride: currentGuard)
        if clearedUsage, !invalidatedAccountState {
            self.persistWidgetSnapshot(reason: "codex-account-invalidate")
        }
    }

    func seedCodexAccountScopedRefreshGuard(
        source: CodexActiveSource? = nil,
        accountEmail: String?)
    {
        let resolvedSource = source ?? self.settings.codexResolvedActiveSource
        let resolvedEmail = Self.normalizeCodexAccountScopedEmail(accountEmail)
        let currentIdentity = self.currentCodexRuntimeIdentity(
            source: resolvedSource,
            preferCurrentSnapshot: false,
            allowLastKnownLiveFallback: false)
        let resolvedIdentity = CodexIdentityMatcher.normalized(
            currentIdentity == .unresolved ? CodexIdentityResolver.resolve(accountId: nil, email: resolvedEmail) :
                currentIdentity,
            fallbackEmail: resolvedEmail ?? "")
        let accountKey = Self.normalizeCodexAccountScopedKey(resolvedEmail ?? Self.email(for: resolvedIdentity))
        guard resolvedIdentity != .unresolved || accountKey != nil else { return }
        self.lastCodexAccountScopedRefreshGuard = CodexAccountScopedRefreshGuard(
            source: resolvedSource,
            identity: resolvedIdentity,
            accountKey: accountKey,
            authFingerprint: self.currentCodexAuthFingerprint(source: resolvedSource))
    }

    func currentCodexAccountScopedRefreshGuard(
        preferCurrentSnapshot: Bool = true,
        allowLastKnownLiveFallback: Bool = true) -> CodexAccountScopedRefreshGuard
    {
        CodexAccountScopedRefreshGuard(
            source: self.settings.codexResolvedActiveSource,
            identity: self.currentCodexRuntimeIdentity(
                source: self.settings.codexResolvedActiveSource,
                preferCurrentSnapshot: preferCurrentSnapshot,
                allowLastKnownLiveFallback: allowLastKnownLiveFallback),
            accountKey: self.codexAccountScopedRefreshKey(
                preferCurrentSnapshot: preferCurrentSnapshot,
                allowLastKnownLiveFallback: allowLastKnownLiveFallback),
            authFingerprint: self.currentCodexAuthFingerprint(source: self.settings.codexResolvedActiveSource))
    }

    func currentCodexOpenAIWebRefreshGuard() -> CodexAccountScopedRefreshGuard {
        let source = self.settings.codexResolvedActiveSource
        let accountKey: String? = switch self.settings.codexResolvedActiveSource {
        case .liveSystem:
            Self
                .normalizeCodexAccountScopedKey(self.settings.codexAccountReconciliationSnapshot.liveSystemAccount?
                    .email)
        case .managedAccount:
            Self.normalizeCodexAccountScopedKey(self.currentManagedCodexRuntimeEmail())
        case let .profileHome(path):
            Self.normalizeCodexAccountScopedKey(self.currentProfileCodexRuntimeEmail(path: path))
        }
        return CodexAccountScopedRefreshGuard(
            source: source,
            identity: self.currentCodexOpenAIWebIdentity(source: source),
            accountKey: accountKey,
            authFingerprint: self.currentCodexAuthFingerprint(source: source))
    }

    func freshCodexAccountScopedRefreshGuard(
        preferCurrentSnapshot: Bool = true,
        allowLastKnownLiveFallback: Bool = true) -> CodexAccountScopedRefreshGuard
    {
        self.settings.invalidateCodexAccountReconciliationSnapshotCache()
        return self.currentCodexAccountScopedRefreshGuard(
            preferCurrentSnapshot: preferCurrentSnapshot,
            allowLastKnownLiveFallback: allowLastKnownLiveFallback)
    }

    func freshCodexOpenAIWebRefreshGuard() -> CodexAccountScopedRefreshGuard {
        self.settings.invalidateCodexAccountReconciliationSnapshotCache()
        return self.currentCodexOpenAIWebRefreshGuard()
    }

    func shouldApplyCodexUsageResult(
        expectedGuard: CodexAccountScopedRefreshGuard,
        usage: UsageSnapshot) -> Bool
    {
        let currentGuard = self.freshCodexAccountScopedRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }
        let fingerprintsAllowApply = Self.codexGuardAuthFingerprintAllowsUsageApply(
            currentGuard,
            expectedGuard)
        let expectedAuthFingerprint = CodexAuthFingerprint.normalize(expectedGuard.authFingerprint)
        let currentAuthFingerprint = CodexAuthFingerprint.normalize(currentGuard.authFingerprint)
        let canProveNilToCurrentAuth = expectedAuthFingerprint == nil && currentAuthFingerprint != nil
        let resultIdentity = CodexIdentityResolver.resolve(accountId: nil, email: usage.accountEmail(for: .codex))
        let resultAccountKey = Self.normalizeCodexAccountScopedKey(usage.accountEmail(for: .codex))
        let resultMatchesCurrentAccountKey = Self.codexUsageResultAccountKeyMatchesCurrentGuard(
            resultAccountKey,
            expectedGuard: expectedGuard,
            currentGuard: currentGuard)

        if expectedGuard.identity != .unresolved {
            guard Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard) else { return false }
            guard resultMatchesCurrentAccountKey else { return false }
            if fingerprintsAllowApply {
                return true
            }
            guard canProveNilToCurrentAuth else { return false }
            return resultIdentity == currentGuard.identity ||
                (resultAccountKey != nil && resultAccountKey == currentGuard.accountKey)
        }

        if currentGuard.identity != .unresolved {
            guard resultIdentity == currentGuard.identity else { return false }
            return fingerprintsAllowApply || canProveNilToCurrentAuth
        }

        switch currentGuard.source {
        case .liveSystem:
            guard resultIdentity != .unresolved else { return false }
            if fingerprintsAllowApply {
                return true
            }
            guard canProveNilToCurrentAuth else { return false }
            guard let currentAccountKey = currentGuard.accountKey else { return true }
            return resultAccountKey == currentAccountKey
        case .managedAccount:
            return false
        case .profileHome:
            return false
        }
    }

    func shouldApplyCodexScopedFailure(expectedGuard: CodexAccountScopedRefreshGuard) -> Bool {
        let currentGuard = self.freshCodexAccountScopedRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }
        guard Self.codexGuardAuthFingerprintMatches(currentGuard, expectedGuard) else { return false }

        if expectedGuard.identity != .unresolved {
            return Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard)
        }

        return currentGuard.identity == .unresolved
    }

    func codexScopedNonUsageSuccessApplyGuard(
        expectedGuard: CodexAccountScopedRefreshGuard) -> CodexAccountScopedRefreshGuard?
    {
        let currentGuard = self.freshCodexAccountScopedRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return nil }
        guard Self.codexGuardAuthFingerprintAllowsUsageApply(currentGuard, expectedGuard) else { return nil }
        guard expectedGuard.identity != .unresolved else { return nil }
        guard Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard) else { return nil }
        return currentGuard
    }

    func shouldApplyCodexScopedNonUsageResult(expectedGuard: CodexAccountScopedRefreshGuard) -> Bool {
        self.codexScopedNonUsageSuccessApplyGuard(expectedGuard: expectedGuard) != nil
    }

    func shouldApplyCodexScopedNonUsageFailure(expectedGuard: CodexAccountScopedRefreshGuard) -> Bool {
        let currentGuard = self.freshCodexAccountScopedRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }
        guard Self.codexGuardAuthFingerprintMatches(currentGuard, expectedGuard) else { return false }
        guard expectedGuard.identity != .unresolved else { return false }
        return Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard)
    }

    func shouldApplyOpenAIDashboardRefreshGuard(
        expectedGuard: CodexAccountScopedRefreshGuard,
        routingTargetEmail: String?) -> Bool
    {
        let normalizedRoutingTargetEmail = CodexIdentityResolver.normalizeEmail(routingTargetEmail)
        let currentGuard = self.freshCodexOpenAIWebRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }
        guard Self.codexGuardAuthFingerprintAllowsUsageApply(currentGuard, expectedGuard) else { return false }

        if expectedGuard.identity != .unresolved {
            return Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard)
        }

        guard case .liveSystem = expectedGuard.source else { return false }
        guard currentGuard.identity == .unresolved else { return false }
        return CodexIdentityResolver.normalizeEmail(
            self.currentCodexOpenAIWebTargetEmail(
                allowCurrentSnapshotFallback: true,
                allowLastKnownLiveFallback: false)) == normalizedRoutingTargetEmail
    }

    func shouldApplyOpenAIWebNonSuccessResult(
        expectedGuard: CodexAccountScopedRefreshGuard,
        routingTargetEmail: String?) -> Bool
    {
        let normalizedRoutingTargetEmail = CodexIdentityResolver.normalizeEmail(routingTargetEmail)
        let currentGuard = self.freshCodexOpenAIWebRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }
        guard Self.codexGuardAuthFingerprintMatches(currentGuard, expectedGuard) else { return false }

        if expectedGuard.identity != .unresolved {
            return Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard)
        }

        guard case .liveSystem = expectedGuard.source else { return false }
        guard currentGuard.identity == .unresolved else { return false }
        return CodexIdentityResolver.normalizeEmail(
            self.currentCodexOpenAIWebTargetEmail(
                allowCurrentSnapshotFallback: true,
                allowLastKnownLiveFallback: false)) == normalizedRoutingTargetEmail
    }

    func shouldApplyOpenAIDashboardPolicyResult(
        expectedGuard: CodexAccountScopedRefreshGuard,
        routingTargetEmail: String?) -> Bool
    {
        let normalizedRoutingTargetEmail = CodexIdentityResolver.normalizeEmail(routingTargetEmail)
        let currentGuard = self.freshCodexOpenAIWebRefreshGuard()
        guard currentGuard.source == expectedGuard.source else { return false }

        if expectedGuard.identity != .unresolved {
            if Self.codexGuardIdentityAndEmailMatch(currentGuard, expectedGuard) {
                return Self.codexGuardAuthFingerprintMatches(currentGuard, expectedGuard) ||
                    Self.codexGuardAuthFingerprintAllowsUsageApply(currentGuard, expectedGuard)
            }
            return Self.codexGuardAuthFingerprintAllowsProviderTransitionCleanup(currentGuard, expectedGuard)
        }

        guard case .liveSystem = expectedGuard.source else { return false }
        guard currentGuard.identity == .unresolved else { return false }
        guard Self.codexGuardAuthFingerprintMatches(currentGuard, expectedGuard) else { return false }
        return CodexIdentityResolver.normalizeEmail(
            self.currentCodexOpenAIWebTargetEmail(
                allowCurrentSnapshotFallback: true,
                allowLastKnownLiveFallback: false)) == normalizedRoutingTargetEmail
    }

    func codexDashboardKnownOwnerCandidates() -> [CodexDashboardKnownOwnerCandidate] {
        CodexKnownOwnerCatalog.candidates(from: self.settings.codexAccountReconciliationSnapshot)
    }

    func trustedCurrentCodexUsageEmailForDashboardAuthority() -> String? {
        guard let sourceLabel = self.lastSourceLabels[.codex], sourceLabel != "openai-web" else {
            return nil
        }
        return CodexIdentityResolver.normalizeEmail(self.snapshots[.codex]?.accountEmail(for: .codex))
    }

    func currentCodexDashboardExpectedScopedEmail() -> String? {
        switch self.settings.codexResolvedActiveSource {
        case .liveSystem:
            CodexIdentityResolver.normalizeEmail(
                self.settings.codexAccountReconciliationSnapshot.liveSystemAccount?.email)
        case .managedAccount:
            CodexIdentityResolver.normalizeEmail(self.currentManagedCodexRuntimeEmail())
        case let .profileHome(path):
            CodexIdentityResolver.normalizeEmail(self.currentProfileCodexRuntimeEmail(path: path))
        }
    }

    func makeCodexDashboardAuthorityInput(
        dashboard: OpenAIDashboardSnapshot,
        sourceKind: CodexDashboardSourceKind,
        routingTargetEmail: String?) -> CodexDashboardAuthorityInput
    {
        let source = self.settings.codexResolvedActiveSource
        return CodexDashboardAuthorityInput(
            sourceKind: sourceKind,
            proof: CodexDashboardOwnershipProofContext(
                currentIdentity: self.currentCodexOpenAIWebIdentity(source: source),
                expectedScopedEmail: self.currentCodexDashboardExpectedScopedEmail(),
                trustedCurrentUsageEmail: self.trustedCurrentCodexUsageEmailForDashboardAuthority(),
                dashboardSignedInEmail: dashboard.signedInEmail,
                knownOwners: self.codexDashboardKnownOwnerCandidates()),
            routing: CodexDashboardRoutingHints(
                targetEmail: CodexIdentityResolver.normalizeEmail(routingTargetEmail),
                lastKnownDashboardRoutingEmail: CodexIdentityResolver.normalizeEmail(
                    self.lastKnownLiveSystemCodexEmail)))
    }

    func evaluateCodexDashboardAuthority(
        dashboard: OpenAIDashboardSnapshot,
        sourceKind: CodexDashboardSourceKind,
        routingTargetEmail: String?) -> (input: CodexDashboardAuthorityInput, decision: CodexDashboardAuthorityDecision)
    {
        let input = self.makeCodexDashboardAuthorityInput(
            dashboard: dashboard,
            sourceKind: sourceKind,
            routingTargetEmail: routingTargetEmail)
        return (input, CodexDashboardAuthority.evaluate(input))
    }

    func codexDashboardAttachmentEmail(from input: CodexDashboardAuthorityInput) -> String? {
        CodexIdentityResolver.normalizeEmail(
            input.proof.expectedScopedEmail ??
                input.proof.trustedCurrentUsageEmail ??
                input.proof.dashboardSignedInEmail)
    }

    func rememberLiveSystemCodexEmailIfNeeded(_ email: String?) {
        guard case .liveSystem = self.settings.codexResolvedActiveSource else { return }
        guard let normalized = Self.normalizeCodexAccountScopedEmail(email) else { return }
        self.lastKnownLiveSystemCodexEmail = normalized
    }

    nonisolated static func codexGuardAuthFingerprintMatches(
        _ lhs: CodexAccountScopedRefreshGuard,
        _ rhs: CodexAccountScopedRefreshGuard) -> Bool
    {
        let lhsFingerprint = CodexAuthFingerprint.normalize(lhs.authFingerprint)
        let rhsFingerprint = CodexAuthFingerprint.normalize(rhs.authFingerprint)
        if lhsFingerprint != nil || rhsFingerprint != nil {
            return lhsFingerprint == rhsFingerprint
        }
        return true
    }

    nonisolated static func codexGuardAuthFingerprintAllowsUsageApply(
        _ lhs: CodexAccountScopedRefreshGuard,
        _ rhs: CodexAccountScopedRefreshGuard) -> Bool
    {
        if self.codexGuardAuthFingerprintMatches(lhs, rhs) {
            return true
        }
        let lhsFingerprint = CodexAuthFingerprint.normalize(lhs.authFingerprint)
        let rhsFingerprint = CodexAuthFingerprint.normalize(rhs.authFingerprint)
        guard lhsFingerprint != nil, rhsFingerprint != nil else { return false }
        guard case .providerAccount = rhs.identity,
              self.codexGuardIdentityAndEmailMatch(lhs, rhs)
        else { return false }
        guard case .liveSystem = lhs.source else { return true }
        return true
    }

    private nonisolated static func codexGuardAuthFingerprintAllowsProviderTransitionCleanup(
        _ lhs: CodexAccountScopedRefreshGuard,
        _ rhs: CodexAccountScopedRefreshGuard) -> Bool
    {
        let lhsFingerprint = CodexAuthFingerprint.normalize(lhs.authFingerprint)
        let rhsFingerprint = CodexAuthFingerprint.normalize(rhs.authFingerprint)
        guard let lhsFingerprint, let rhsFingerprint, lhsFingerprint != rhsFingerprint else { return false }
        guard case .providerAccount = rhs.identity else { return false }
        guard lhs.identity == rhs.identity else { return false }
        guard let lhsEmail = CodexIdentityResolver.normalizeEmail(lhs.accountKey),
              let rhsEmail = CodexIdentityResolver.normalizeEmail(rhs.accountKey)
        else { return false }
        return lhsEmail != rhsEmail
    }

    nonisolated static func codexScopedRefreshGuardsMatchAccount(
        _ lhs: CodexAccountScopedRefreshGuard,
        _ rhs: CodexAccountScopedRefreshGuard) -> Bool
    {
        guard lhs.source == rhs.source else { return false }
        if lhs == rhs {
            guard case .providerAccount = lhs.identity else { return true }
            return self.codexGuardIdentityAndEmailMatch(lhs, rhs)
        }
        guard lhs.identity != .unresolved,
              self.codexGuardIdentityAndEmailMatch(lhs, rhs),
              lhs.accountKey == rhs.accountKey
        else {
            return false
        }
        return self.codexGuardAuthFingerprintAllowsUsageApply(lhs, rhs)
    }

    private nonisolated static func codexGuardIdentityAndEmailMatch(
        _ lhs: CodexAccountScopedRefreshGuard,
        _ rhs: CodexAccountScopedRefreshGuard) -> Bool
    {
        guard lhs.identity == rhs.identity else { return false }
        guard case .providerAccount = lhs.identity else { return true }
        guard let lhsEmail = CodexIdentityResolver.normalizeEmail(lhs.accountKey),
              let rhsEmail = CodexIdentityResolver.normalizeEmail(rhs.accountKey)
        else { return false }
        return lhsEmail == rhsEmail
    }

    private nonisolated static func codexUsageResultAccountKeyMatchesCurrentGuard(
        _ resultAccountKey: String?,
        expectedGuard: CodexAccountScopedRefreshGuard,
        currentGuard: CodexAccountScopedRefreshGuard) -> Bool
    {
        guard let currentAccountKey = currentGuard.accountKey else { return true }
        guard let resultAccountKey else {
            guard let expectedAccountKey = expectedGuard.accountKey else { return true }
            return expectedAccountKey == currentAccountKey
        }
        return resultAccountKey == currentAccountKey
    }

    func currentCodexAuthFingerprint(source: CodexActiveSource) -> String? {
        let snapshot = self.settings.codexAccountReconciliationSnapshot
        switch source {
        case .liveSystem:
            return CodexAuthFingerprint.normalize(snapshot.liveSystemAccount?.authFingerprint)
        case let .managedAccount(id):
            guard let account = snapshot.storedAccounts.first(where: { $0.id == id }) else { return nil }
            return CodexAuthFingerprint.fingerprint(homePath: account.managedHomePath)
        case let .profileHome(path):
            guard let profileAccount = snapshot.profileHomeAccount(path: path) else {
                guard let normalizedPath = CodexHomeScope.normalizedHomePath(path) else { return nil }
                return CodexAuthFingerprint.fingerprint(homePath: normalizedPath)
            }
            return CodexAuthFingerprint.normalize(profileAccount.authFingerprint)
        }
    }

    func codexAccountScopedRefreshKey(
        preferCurrentSnapshot: Bool = true,
        allowLastKnownLiveFallback: Bool = true) -> String?
    {
        Self.normalizeCodexAccountScopedKey(
            self.codexAccountScopedRefreshEmail(
                preferCurrentSnapshot: preferCurrentSnapshot,
                allowLastKnownLiveFallback: allowLastKnownLiveFallback))
    }

    func codexAccountScopedRefreshEmail(
        preferCurrentSnapshot: Bool = true,
        allowLastKnownLiveFallback: Bool = true) -> String?
    {
        switch self.settings.codexResolvedActiveSource {
        case .liveSystem:
            let liveSystem = Self.normalizeCodexAccountScopedEmail(
                self.settings.codexAccountReconciliationSnapshot.liveSystemAccount?.email)
            if let liveSystem {
                self.lastKnownLiveSystemCodexEmail = liveSystem
                return liveSystem
            }

            if preferCurrentSnapshot,
               let snapshotEmail = Self
                   .normalizeCodexAccountScopedEmail(self.snapshots[.codex]?.accountEmail(for: .codex))
            {
                self.lastKnownLiveSystemCodexEmail = snapshotEmail
                return snapshotEmail
            }

            if allowLastKnownLiveFallback,
               let lastKnown = Self.normalizeCodexAccountScopedEmail(self.lastKnownLiveSystemCodexEmail)
            {
                return lastKnown
            }

            return nil
        case .managedAccount:
            if self.settings.codexSettingsSnapshot(tokenOverride: nil).managedAccountStoreUnreadable {
                return nil
            }
            return self.currentManagedCodexRuntimeEmail()
        case let .profileHome(path):
            return self.currentProfileCodexRuntimeEmail(path: path)
        }
    }

    func currentCodexRuntimeIdentity(
        source: CodexActiveSource,
        preferCurrentSnapshot: Bool,
        allowLastKnownLiveFallback: Bool) -> CodexIdentity
    {
        switch source {
        case .liveSystem:
            if let liveSystem = self.settings.codexAccountReconciliationSnapshot.liveSystemAccount {
                return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: liveSystem)
            }

            if preferCurrentSnapshot,
               let snapshotEmail = Self
                   .normalizeCodexAccountScopedEmail(self.snapshots[.codex]?.accountEmail(for: .codex))
            {
                self.lastKnownLiveSystemCodexEmail = snapshotEmail
                return CodexIdentityResolver.resolve(accountId: nil, email: snapshotEmail)
            }

            if allowLastKnownLiveFallback,
               let lastKnown = Self.normalizeCodexAccountScopedEmail(self.lastKnownLiveSystemCodexEmail)
            {
                return CodexIdentityResolver.resolve(accountId: nil, email: lastKnown)
            }

            return .unresolved
        case .managedAccount:
            guard !self.settings.codexSettingsSnapshot(tokenOverride: nil).managedAccountStoreUnreadable else {
                return .unresolved
            }
            guard let activeStoredAccount = self.settings.codexAccountReconciliationSnapshot.activeStoredAccount else {
                return .unresolved
            }
            return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: activeStoredAccount)
        case let .profileHome(path):
            guard let profileAccount = self.settings.codexAccountReconciliationSnapshot.profileHomeAccount(path: path)
            else {
                return .unresolved
            }
            return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: profileAccount)
        }
    }

    private func currentCodexOpenAIWebIdentity(source: CodexActiveSource) -> CodexIdentity {
        switch source {
        case .liveSystem:
            guard let liveSystem = self.settings.codexAccountReconciliationSnapshot.liveSystemAccount else {
                return .unresolved
            }
            return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: liveSystem)
        case .managedAccount:
            guard !self.settings.codexSettingsSnapshot(tokenOverride: nil).managedAccountStoreUnreadable else {
                return .unresolved
            }
            guard let activeStoredAccount = self.settings.codexAccountReconciliationSnapshot.activeStoredAccount else {
                return .unresolved
            }
            return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: activeStoredAccount)
        case let .profileHome(path):
            guard let profileAccount = self.settings.codexAccountReconciliationSnapshot.profileHomeAccount(path: path)
            else {
                return .unresolved
            }
            return self.settings.codexAccountReconciliationSnapshot.runtimeIdentity(for: profileAccount)
        }
    }

    func currentManagedCodexRuntimeEmail() -> String? {
        guard !self.settings.codexSettingsSnapshot(tokenOverride: nil).managedAccountStoreUnreadable else {
            return nil
        }
        guard let activeStoredAccount = self.settings.codexAccountReconciliationSnapshot.activeStoredAccount else {
            return nil
        }
        return Self.normalizeCodexAccountScopedEmail(
            self.settings.codexAccountReconciliationSnapshot.runtimeEmail(for: activeStoredAccount))
    }

    func currentProfileCodexRuntimeEmail(path: String) -> String? {
        guard let profileAccount = self.settings.codexAccountReconciliationSnapshot.profileHomeAccount(path: path)
        else {
            return nil
        }
        return Self.normalizeCodexAccountScopedEmail(profileAccount.email)
    }

    private func clearCodexOpenAIWebStateForAccountTransition(targetEmail: String?) {
        self.invalidateOpenAIDashboardRefreshTask()
        if self.settings.codexCookieSource.isEnabled,
           let normalizedTarget = Self.normalizeCodexAccountScopedEmail(targetEmail)
        {
            let scope = self.codexCookieCacheScopeForOpenAIWeb()
            let isolationKey = Self.openAIWebTargetIsolationKey(email: normalizedTarget, scope: scope)
            let previousIsolationKey = self.lastOpenAIDashboardTargetIsolationKey
            self.lastOpenAIDashboardTargetEmail = normalizedTarget
            self.lastOpenAIDashboardTargetIsolationKey = isolationKey
            if let previousIsolationKey, previousIsolationKey != isolationKey {
                self.openAIWebAccountDidChange = true
                self.openAIDashboardCookieImportStatus = L("Codex account changed; importing browser cookies…")
            } else {
                self.openAIDashboardCookieImportStatus = nil
            }
            self.openAIDashboardRequiresLogin = true
        } else {
            self.lastOpenAIDashboardTargetEmail = Self.normalizeCodexAccountScopedEmail(targetEmail)
            self.lastOpenAIDashboardTargetIsolationKey = nil
            self.openAIWebAccountDidChange = false
            self.openAIDashboardRequiresLogin = false
            self.openAIDashboardCookieImportStatus = nil
        }

        self.openAIDashboard = nil
        self.openAIDashboardAttachmentAuthorized = false
        self.lastOpenAIDashboardSnapshot = nil
        self.lastOpenAIDashboardAttachmentAuthorized = false
        self.lastOpenAIDashboardError = nil
        self.openAIDashboardCookieImportDebugLog = nil
        self.lastOpenAIDashboardCookieImportAttemptAt = nil
        self.lastOpenAIDashboardCookieImportEmail = nil
    }

    static func normalizeCodexAccountScopedEmail(_ email: String?) -> String? {
        guard let trimmed = email?.trimmingCharacters(in: .whitespacesAndNewlines), !trimmed.isEmpty else {
            return nil
        }
        return trimmed
    }

    static func normalizeCodexAccountScopedKey(_ email: String?) -> String? {
        self.normalizeCodexAccountScopedEmail(email)?.lowercased()
    }

    static func codexIdentityGuardKey(_ identity: CodexIdentity) -> String? {
        switch identity {
        case let .providerAccount(id):
            "provider:\(id)"
        case let .emailOnly(normalizedEmail):
            "email:\(normalizedEmail)"
        case .unresolved:
            nil
        }
    }

    private static func email(for identity: CodexIdentity) -> String? {
        switch identity {
        case .providerAccount, .unresolved:
            nil
        case let .emailOnly(normalizedEmail):
            normalizedEmail
        }
    }
}
