import Foundation
import Testing
@testable import CodexBarCore

private struct KimiStubClaudeFetcher: ClaudeUsageFetching {
    func loadLatestUsage(model _: String) async throws -> ClaudeUsageSnapshot {
        throw ClaudeUsageError.parseFailed("stub")
    }

    func debugRawProbe(model _: String) async -> String {
        "stub"
    }

    func detectVersion() -> String? {
        nil
    }
}

private func makeKimiFetchContext(
    sourceMode: ProviderSourceMode,
    environment: [String: String] = [:],
    settings: ProviderSettingsSnapshot? = nil) -> ProviderFetchContext
{
    let env = environment
    return ProviderFetchContext(
        runtime: .app,
        sourceMode: sourceMode,
        includeCredits: false,
        webTimeout: 1,
        webDebugDumpHTML: false,
        verbose: false,
        env: env,
        settings: settings,
        fetcher: UsageFetcher(environment: env),
        claudeFetcher: KimiStubClaudeFetcher(),
        browserDetection: BrowserDetection(cacheTTL: 0))
}

private func makeTemporaryKimiCodeHome() throws -> URL {
    let home = FileManager.default.temporaryDirectory
        .appendingPathComponent("CodexBar-KimiCode-\(UUID().uuidString)", isDirectory: true)
    try FileManager.default.createDirectory(
        at: home,
        withIntermediateDirectories: true,
        attributes: [.posixPermissions: 0o700])
    return home
}

private func writeKimiCodeCredential(
    home: URL,
    accessToken: String,
    refreshToken: String = "refresh",
    expiresAt: Any?) throws -> URL
{
    let credentials = home.appendingPathComponent("credentials", isDirectory: true)
    try FileManager.default.createDirectory(at: credentials, withIntermediateDirectories: true)
    var payload: [String: Any] = [
        "access_token": accessToken,
        "refresh_token": refreshToken,
    ]
    if let expiresAt {
        payload["expires_at"] = expiresAt
    }
    let url = credentials.appendingPathComponent("kimi-code.json")
    try JSONSerialization.data(withJSONObject: payload, options: [.prettyPrinted, .sortedKeys]).write(to: url)
    return url
}

private actor KimiOrderedCredentialTransport: ProviderHTTPTransport {
    private var headers: [String] = []

    func authorizationHeaders() -> [String] {
        self.headers
    }

    func data(for request: URLRequest) async throws -> (Data, URLResponse) {
        let authorization = request.value(forHTTPHeaderField: "Authorization") ?? ""
        self.headers.append(authorization)
        let statusCode: Int
        let body: String
        switch authorization {
        case "Bearer api-bad":
            statusCode = 401
            body = #"{"error":"unauthorized"}"#
        case "Bearer cli-ok":
            statusCode = 200
            body = #"{"usage":{"limit":"100","used":"25","remaining":"75"},"limits":[]}"#
        default:
            throw URLError(.userAuthenticationRequired)
        }
        let url = try #require(request.url)
        let response = try #require(HTTPURLResponse(
            url: url,
            statusCode: statusCode,
            httpVersion: nil,
            headerFields: ["Content-Type": "application/json"]))
        return (Data(body.utf8), response)
    }
}

struct KimiSettingsReaderTests {
    @Test
    func `reads token from environment variable`() {
        let env = ["KIMI_AUTH_TOKEN": "test.jwt.token"]
        let token = KimiSettingsReader.authToken(environment: env)
        #expect(token == "test.jwt.token")
    }

    @Test
    func `reads API key from preferred environment variable`() {
        let env = ["KIMI_CODE_API_KEY": "kimi-code-token"]
        let token = KimiSettingsReader.apiKey(environment: env)
        #expect(token == "kimi-code-token")
    }

    @Test
    func `does not consume generic Kimi API key environment variable`() {
        let env = ["KIMI_API_KEY": "'kimi-api-token'"]
        let token = KimiSettingsReader.apiKey(environment: env)
        #expect(token == nil)
    }

    @Test
    func `uses code specific API key when generic Kimi API key also exists`() {
        let env = [
            "KIMI_API_KEY": "generic-kimi-token",
            "KIMI_CODE_API_KEY": "kimi-code-token",
        ]
        let token = KimiSettingsReader.apiKey(environment: env)
        #expect(token == "kimi-code-token")
    }

    @Test
    func `reuses fresh CLI credential without modifying it`() throws {
        let home = try makeTemporaryKimiCodeHome()
        defer { try? FileManager.default.removeItem(at: home) }
        let now = Date(timeIntervalSince1970: 1_800_000_000)
        let credentialURL = try writeKimiCodeCredential(
            home: home,
            accessToken: "oauth",
            expiresAt: now.addingTimeInterval(3600).timeIntervalSince1970)
        let originalData = try Data(contentsOf: credentialURL)
        let originalModificationDate = try #require(
            FileManager.default.attributesOfItem(atPath: credentialURL.path)[.modificationDate] as? Date)
        let environment = ["KIMI_CODE_HOME": home.path]

        let token = KimiSettingsReader.kimiCodeAccessToken(environment: environment, now: now)
        let headers = KimiSettingsReader.kimiCodeIdentityHeaders(environment: environment)

        #expect(token == "oauth")
        #expect(headers["X-Msh-Platform"] == "kimi_code_cli")
        #expect(headers["X-Msh-Device-Id"]?.isEmpty == false)
        #expect(try Data(contentsOf: credentialURL) == originalData)
        let finalModificationDate = try #require(
            FileManager.default.attributesOfItem(atPath: credentialURL.path)[.modificationDate] as? Date)
        #expect(finalModificationDate == originalModificationDate)

        let deviceURL = home.appendingPathComponent("device_id")
        let permissions = try #require(
            FileManager.default.attributesOfItem(atPath: deviceURL.path)[.posixPermissions] as? NSNumber)
        #expect(permissions.intValue & 0o777 == 0o600)
    }

    @Test
    func `rejects expired or missing-expiry CLI credentials`() throws {
        let now = Date()
        for expiresAt: Any? in [now.addingTimeInterval(30).timeIntervalSince1970, nil, "not-a-time"] {
            let home = try makeTemporaryKimiCodeHome()
            defer { try? FileManager.default.removeItem(at: home) }
            _ = try writeKimiCodeCredential(
                home: home,
                accessToken: "oauth",
                expiresAt: expiresAt)
            let environment = ["KIMI_CODE_HOME": home.path]

            #expect(KimiSettingsReader.hasKimiCodeCredential(environment: environment))
            #expect(KimiSettingsReader.kimiCodeAccessToken(environment: environment, now: now) == nil)
        }
    }

    @Test
    func `keeps explicit key separate and isolates CLI credential from endpoint overrides`() throws {
        let home = try makeTemporaryKimiCodeHome()
        defer { try? FileManager.default.removeItem(at: home) }
        _ = try writeKimiCodeCredential(
            home: home,
            accessToken: "oauth",
            expiresAt: Date().addingTimeInterval(3600).timeIntervalSince1970)

        let explicit = ProviderTokenResolver.resolution(for: .kimi, kind: .secondary, environment: [
            "KIMI_CODE_API_KEY": "explicit",
            "KIMI_CODE_HOME": home.path,
        ])
        #expect(explicit?.token == "explicit")
        #expect(explicit?.source == .environment)
        #expect(KimiSettingsReader.kimiCodeAccessToken(environment: [
            "KIMI_CODE_API_KEY": "explicit",
            "KIMI_CODE_HOME": home.path,
        ]) == "oauth")

        for key in ["KIMI_CODE_BASE_URL", "KIMI_CODE_OAUTH_HOST", "KIMI_OAUTH_HOST"] {
            let environment = [
                "KIMI_CODE_HOME": home.path,
                key: "https://proxy.example.com",
            ]
            #expect(KimiSettingsReader.hasKimiCodeCredential(environment: environment) == false)
            #expect(ProviderTokenResolver.resolution(for: .kimi, kind: .secondary, environment: environment) == nil)
        }
    }

    @Test
    func `uses default code API base URL when override is absent`() throws {
        let url = try KimiSettingsReader.codeAPIBaseURL(environment: [:])
        #expect(url == KimiSettingsReader.defaultCodeAPIBaseURL)
    }

    @Test
    func `uses custom code API base URL when valid`() throws {
        let env = ["KIMI_CODE_BASE_URL": "https://proxy.example.com/kimi"]
        let url = try KimiSettingsReader.codeAPIBaseURL(environment: env)
        #expect(url.absoluteString == "https://proxy.example.com/kimi")
    }

    @Test
    func `rejects invalid code API base URL`() {
        let env = ["KIMI_CODE_BASE_URL": "not a url"]

        #expect(throws: KimiAPIError.invalidRequest(
            "Kimi Code API base URL must use HTTPS without user info"))
        {
            try KimiSettingsReader.codeAPIBaseURL(environment: env)
        }
    }

    @Test
    func `rejects insecure code API base URL`() {
        let env = ["KIMI_CODE_BASE_URL": "http://proxy.example.com/kimi"]

        #expect(throws: KimiAPIError.invalidRequest(
            "Kimi Code API base URL must use HTTPS without user info"))
        {
            try KimiSettingsReader.codeAPIBaseURL(environment: env)
        }
    }

    @Test
    func `rejects code API base URL containing user info`() {
        let env = ["KIMI_CODE_BASE_URL": "https://api.kimi.com@proxy.example.com/kimi"]

        #expect(throws: KimiAPIError.invalidRequest(
            "Kimi Code API base URL must use HTTPS without user info"))
        {
            try KimiSettingsReader.codeAPIBaseURL(environment: env)
        }
    }

    @Test
    func `normalizes quoted token`() {
        let env = ["KIMI_AUTH_TOKEN": "\"test.jwt.token\""]
        let token = KimiSettingsReader.authToken(environment: env)
        #expect(token == "test.jwt.token")
    }

    @Test
    func `returns nil when missing`() {
        let env: [String: String] = [:]
        let token = KimiSettingsReader.authToken(environment: env)
        #expect(token == nil)
    }

    @Test
    func `returns nil when empty`() {
        let env = ["KIMI_AUTH_TOKEN": ""]
        let token = KimiSettingsReader.authToken(environment: env)
        #expect(token == nil)
    }

    @Test
    func `normalizes lowercase environment key`() {
        let env = ["kimi_auth_token": "test.jwt.token"]
        let token = KimiSettingsReader.authToken(environment: env)
        #expect(token == "test.jwt.token")
    }
}

struct KimiAPIFetchStrategyTests {
    @Test
    func `cookie source off disables every browser import path`() {
        let offContext = makeKimiFetchContext(
            sourceMode: .auto,
            settings: .make(kimi: .init(cookieSource: .off, manualCookieHeader: nil)))
        let autoContext = makeKimiFetchContext(
            sourceMode: .auto,
            settings: .make(kimi: .init(cookieSource: .auto, manualCookieHeader: nil)))

        #expect(KimiBrowserImportPolicy.allowsImport(offContext) == false)
        #expect(KimiBrowserImportPolicy.allowsImport(autoContext))
        #expect(ProviderTokenResolver.resolution(for: .kimi, environment: [:]) == nil)
    }

    @Test
    func `cookie source off skips monthly enrichment resolution`() async throws {
        let transport = ProviderHTTPTransportStub { request in
            let url = try #require(request.url)
            #expect(url.path == "/coding/v1/usages")
            let response = try #require(HTTPURLResponse(
                url: url,
                statusCode: 200,
                httpVersion: nil,
                headerFields: ["Content-Type": "application/json"]))
            let data = Data(#"{"usage":{"limit":"100","used":"25","remaining":"75"},"limits":[]}"#.utf8)
            return (data, response)
        }
        let strategy = KimiAPIFetchStrategy(
            transport: transport,
            resolveWebAuthToken: { _ in
                Issue.record("Cookie source Off must not resolve desktop or browser sessions")
                return "unexpected-web-token"
            })
        let context = makeKimiFetchContext(
            sourceMode: .api,
            environment: ["KIMI_CODE_API_KEY": "api-token"],
            settings: .make(kimi: .init(cookieSource: .off, manualCookieHeader: nil)))

        let result = try await strategy.fetch(context)

        #expect(result.usage.primary?.usedPercent == 25)
        #expect(result.usage.extraRateWindows == nil)
        #expect(await transport.requests().count == 1)
    }

    @Test
    func `code API usage enriches monthly pool from explicit web session`() async throws {
        let transport = ProviderHTTPTransportStub { request in
            let url = try #require(request.url)
            let response = try #require(HTTPURLResponse(
                url: url,
                statusCode: 200,
                httpVersion: nil,
                headerFields: ["Content-Type": "application/json"]))
            if url.path == "/coding/v1/usages" {
                return (
                    Data(#"{"usage":{"limit":"100","used":"25","remaining":"75"},"limits":[]}"#.utf8),
                    response)
            }
            #expect(url.path.hasSuffix("/GetSubscriptionStats"))
            #expect(request.value(forHTTPHeaderField: "Cookie") == "kimi-auth=desktop-token")
            return (
                Data(#"{"subscriptionBalance":{"feature":"FEATURE_OMNI","type":"SUBSCRIPTION","amountUsedRatio":0.42}}"#
                    .utf8),
                response)
        }
        let strategy = KimiAPIFetchStrategy(
            transport: transport,
            resolveWebAuthToken: { _ in "desktop-token" })
        let context = makeKimiFetchContext(
            sourceMode: .api,
            environment: ["KIMI_CODE_API_KEY": "api-token"],
            settings: .make(kimi: .init(cookieSource: .auto, manualCookieHeader: nil)))

        let result = try await strategy.fetch(context)
        let monthly = result.usage.extraRateWindows?.first { $0.id == "kimi-monthly" }

        #expect(monthly?.window.usedPercent == 42)
        #expect(await transport.requests().count == 2)
    }

    @Test
    func `auto mode accepts CLI credential and reports expired remediation`() async throws {
        let home = try makeTemporaryKimiCodeHome()
        defer { try? FileManager.default.removeItem(at: home) }
        _ = try writeKimiCodeCredential(
            home: home,
            accessToken: "expired",
            expiresAt: Date().addingTimeInterval(-60).timeIntervalSince1970)
        let strategy = KimiCLICredentialFetchStrategy()
        let context = makeKimiFetchContext(
            sourceMode: .auto,
            environment: ["KIMI_CODE_HOME": home.path])

        #expect(await strategy.isAvailable(context))
        await #expect(throws: KimiAPIError.expiredCodeCredential) {
            try await strategy.fetch(context)
        }
        #expect(strategy.shouldFallback(on: KimiAPIError.expiredCodeCredential, context: context))
    }

    @Test
    func `explicit API mode ignores fresh CLI credential`() async throws {
        let home = try makeTemporaryKimiCodeHome()
        defer { try? FileManager.default.removeItem(at: home) }
        _ = try writeKimiCodeCredential(
            home: home,
            accessToken: "oauth",
            expiresAt: Date().addingTimeInterval(3600).timeIntervalSince1970)
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(
            sourceMode: .api,
            environment: ["KIMI_CODE_HOME": home.path])

        await #expect(throws: KimiAPIError.missingAPIKey) {
            try await strategy.fetch(context)
        }
    }

    @Test
    func `rejected CLI credential keeps CLI remediation`() {
        let cliError = KimiCLICredentialFetchStrategy.normalizedCodeAPIError(KimiAPIError.invalidAPIKey)
        let keyError = KimiCLICredentialFetchStrategy.normalizedCodeAPIError(KimiAPIError.apiError("failed"))

        #expect(cliError as? KimiAPIError == .invalidCodeCredential)
        #expect(keyError as? KimiAPIError == .apiError("failed"))
    }

    @Test
    func `auto retries fresh CLI credential after rejected API key`() async throws {
        let home = try makeTemporaryKimiCodeHome()
        defer { try? FileManager.default.removeItem(at: home) }
        _ = try writeKimiCodeCredential(
            home: home,
            accessToken: "cli-ok",
            expiresAt: Date().addingTimeInterval(3600).timeIntervalSince1970)
        let transport = KimiOrderedCredentialTransport()
        let pipeline = ProviderFetchPipeline { _ in
            [
                KimiAPIFetchStrategy(transport: transport),
                KimiCLICredentialFetchStrategy(transport: transport),
            ]
        }
        let context = makeKimiFetchContext(
            sourceMode: .auto,
            environment: [
                "KIMI_CODE_API_KEY": "api-bad",
                "KIMI_CODE_HOME": home.path,
            ])

        let outcome = await pipeline.fetch(context: context, provider: .kimi)
        let result = try outcome.result.get()

        #expect(result.sourceLabel == "Kimi Code CLI")
        #expect(outcome.attempts.map(\.strategyID) == ["kimi.api", "kimi.cli"])
        #expect(await transport.authorizationHeaders() == [
            "Bearer api-bad",
            "Bearer cli-ok",
        ])
    }

    @Test
    func `auto mode falls back from invalid API key to web cookies`() {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .auto)

        #expect(strategy.shouldFallback(on: KimiAPIError.invalidAPIKey, context: context))
    }

    @Test
    func `explicit API mode does not fall back from invalid API key`() {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .api)

        #expect(strategy.shouldFallback(on: KimiAPIError.invalidAPIKey, context: context) == false)
    }

    @Test
    func `explicit API mode reports API key remediation when key is missing`() async {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .api)

        await #expect(throws: KimiAPIError.missingAPIKey) {
            try await strategy.fetch(context)
        }
    }

    @Test
    func `auto mode falls back from API response decoding failure`() {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .auto)
        let error = DecodingError.dataCorrupted(
            DecodingError.Context(codingPath: [], debugDescription: "Unexpected Kimi payload"))

        #expect(strategy.shouldFallback(on: error, context: context))
    }

    @Test
    func `explicit API mode surfaces response decoding failure`() {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .api)
        let error = DecodingError.dataCorrupted(
            DecodingError.Context(codingPath: [], debugDescription: "Unexpected Kimi payload"))

        #expect(strategy.shouldFallback(on: error, context: context) == false)
    }

    @Test
    func `auto mode does not start web fallback after cancellation`() {
        let strategy = KimiAPIFetchStrategy()
        let context = makeKimiFetchContext(sourceMode: .auto)

        #expect(strategy.shouldFallback(on: CancellationError(), context: context) == false)
        #expect(strategy.shouldFallback(on: URLError(.cancelled), context: context) == false)
    }
}

struct KimiUsageResponseParsingTests {
    @Test
    func `parses valid response`() throws {
        let json = """
        {
          "usages": [
            {
              "scope": "FEATURE_CODING",
              "detail": {
                "limit": "2048",
                "used": "375",
                "remaining": "1673",
                "resetTime": "2026-01-09T15:23:13.373329235Z"
              },
              "limits": [
                {
                  "window": {
                    "duration": 300,
                    "timeUnit": "TIME_UNIT_MINUTE"
                  },
                  "detail": {
                    "limit": "200",
                    "used": "200",
                    "resetTime": "2026-01-06T15:05:24.374187075Z"
                  }
                }
              ]
            }
          ]
        }
        """

        let response = try JSONDecoder().decode(KimiUsageResponse.self, from: Data(json.utf8))

        #expect(response.usages.count == 1)
        let usage = response.usages[0]
        #expect(usage.scope == "FEATURE_CODING")
        #expect(usage.detail.limit == "2048")
        #expect(usage.detail.used == "375")
        #expect(usage.detail.remaining == "1673")
        #expect(usage.detail.resetTime == "2026-01-09T15:23:13.373329235Z")

        #expect(usage.limits?.count == 1)
        let rateLimit = usage.limits?.first
        #expect(rateLimit?.window.duration == 300)
        #expect(rateLimit?.window.timeUnit == "TIME_UNIT_MINUTE")
        #expect(rateLimit?.detail.limit == "200")
        #expect(rateLimit?.detail.used == "200")
    }

    @Test
    func `parses response without rate limits`() throws {
        let json = """
        {
          "usages": [
            {
              "scope": "FEATURE_CODING",
              "detail": {
                "limit": "2048",
                "used": "375",
                "remaining": "1673",
                "resetTime": "2026-01-09T15:23:13.373329235Z"
              },
              "limits": []
            }
          ]
        }
        """

        let response = try JSONDecoder().decode(KimiUsageResponse.self, from: Data(json.utf8))
        #expect(response.usages.first?.limits?.isEmpty == true)
    }

    @Test
    func `parses response with null limits`() throws {
        let json = """
        {
          "usages": [
            {
              "scope": "FEATURE_CODING",
              "detail": {
                "limit": "2048",
                "used": "375",
                "remaining": "1673",
                "resetTime": "2026-01-09T15:23:13.373329235Z"
              },
              "limits": null
            }
          ]
        }
        """

        let response = try JSONDecoder().decode(KimiUsageResponse.self, from: Data(json.utf8))
        #expect(response.usages.first?.limits == nil)
    }

    @Test
    func `parses code API usage response`() throws {
        let json = """
        {
          "usage": {
            "limit": "2048",
            "used": "375",
            "remaining": "1673",
            "resetTime": "2026-01-09T15:23:13.373329235Z"
          },
          "limits": [
            {
              "window": {
                "duration": 300,
                "timeUnit": "TIME_UNIT_MINUTE"
              },
              "detail": {
                "limit": "200",
                "used": "19",
                "remaining": "181",
                "resetTime": "2026-01-06T15:05:24.374187075Z"
              }
            }
          ]
        }
        """

        let snapshot = try KimiUsageFetcher._parseCodeAPIUsageForTesting(Data(json.utf8))
        #expect(snapshot.weekly.limit == "2048")
        #expect(snapshot.weekly.used == "375")
        #expect(snapshot.rateLimit?.limit == "200")
        #expect(snapshot.rateLimit?.used == "19")

        let usage = snapshot.toUsageSnapshot()
        #expect(abs((usage.primary?.usedPercent ?? -1) - 18.3105) < 0.001)
        #expect(usage.primary?.resetDescription == "375/2048 requests")
        #expect(abs((usage.secondary?.usedPercent ?? -1) - 9.5) < 0.001)
        #expect(usage.secondary?.windowMinutes == 300)
        #expect(usage.secondary?.resetDescription == "Rate: 19/200 per 5 hours")
    }

    @Test
    func `sends CLI identity headers on the existing usage request`() async throws {
        let baseURL = try #require(URL(string: "https://api.kimi.com"))
        let identityHeaders = [
            "User-Agent": "CodexBar/test",
            "X-Msh-Platform": "kimi_code_cli",
            "X-Msh-Device-Id": "test-device-id",
        ]
        let transport = ProviderHTTPTransportHandler { request in
            #expect(request.url?.path == "/coding/v1/usages")
            #expect(request.value(forHTTPHeaderField: "Authorization") == "Bearer oauth-token")
            for (name, value) in identityHeaders {
                #expect(request.value(forHTTPHeaderField: name) == value)
            }
            let response = try #require(HTTPURLResponse(
                url: request.url ?? baseURL,
                statusCode: 200,
                httpVersion: nil,
                headerFields: ["Content-Type": "application/json"]))
            let data = Data("""
            {
              "usage": {"limit": "100", "used": "25", "remaining": "75"},
              "limits": []
            }
            """.utf8)
            return (data, response)
        }

        let snapshot = try await KimiUsageFetcher.fetchCodeAPIUsage(
            apiKey: "oauth-token",
            baseURL: baseURL,
            identityHeaders: identityHeaders,
            transport: transport)

        #expect(snapshot.toUsageSnapshot().primary?.usedPercent == 25)
    }

    @Test
    func `converts weekly-only usage into primary quota lane`() {
        let snapshot = KimiUsageSnapshot(
            weekly: KimiUsageDetail(
                limit: "2048",
                used: "512",
                remaining: "1536",
                resetTime: "2026-01-09T15:23:13Z"),
            rateLimit: nil,
            updatedAt: Date(timeIntervalSince1970: 1_800_000_000))

        let usage = snapshot.toUsageSnapshot()

        #expect(usage.primary?.usedPercent == 25)
        #expect(usage.primary?.resetDescription == "512/2048 requests")
        #expect(usage.secondary == nil)
    }

    @Test
    func `parses official numeric values and reset key variants`() throws {
        let json = """
        {
          "usage": {
            "limit": 1000,
            "used": 40,
            "remaining": 960,
            "resetAt": "2026-01-09T15:23:13Z"
          },
          "limits": [
            {
              "window": {
                "duration": 300,
                "timeUnit": "TIME_UNIT_MINUTE"
              },
              "detail": {
                "limit": 100,
                "remaining": 99,
                "reset_at": "2026-01-06T13:33:02Z"
              }
            }
          ]
        }
        """

        let snapshot = try KimiUsageFetcher._parseCodeAPIUsageForTesting(Data(json.utf8))

        #expect(snapshot.weekly.limit == "1000")
        #expect(snapshot.weekly.used == "40")
        #expect(snapshot.weekly.remaining == "960")
        #expect(snapshot.weekly.resetTime == "2026-01-09T15:23:13Z")
        #expect(snapshot.rateLimit?.limit == "100")
        #expect(snapshot.rateLimit?.used == nil)
        #expect(snapshot.rateLimit?.remaining == "99")
        #expect(snapshot.rateLimit?.resetTime == "2026-01-06T13:33:02Z")
        #expect(snapshot.toUsageSnapshot().primary?.windowMinutes == KimiProviderDescriptor.weeklyWindowMinutes)
        #expect(snapshot.toUsageSnapshot().secondary?.windowMinutes == 300)
        #expect(snapshot.toUsageSnapshot().secondary?.resetDescription == "Rate: 1/100 per 5 hours")
    }

    @Test
    func `derives rate window duration from API units`() throws {
        let json = """
        {
          "usage": {"limit": 1000, "used": 40, "remaining": 960},
          "limits": [
            {
              "window": {"duration": 2, "timeUnit": "TIME_UNIT_HOUR"},
              "detail": {"limit": 100, "used": 25, "remaining": 75}
            }
          ]
        }
        """

        let usage = try KimiUsageFetcher._parseCodeAPIUsageForTesting(Data(json.utf8)).toUsageSnapshot()

        #expect(usage.secondary?.windowMinutes == 120)
        #expect(usage.secondary?.resetDescription == "Rate: 25/100 per 2 hours")
    }

    @Test
    func `converts supported window units and rejects invalid durations`() {
        #expect(KimiWindow(duration: 300, timeUnit: "TIME_UNIT_MINUTE").durationMinutes == 300)
        #expect(KimiWindow(duration: 5, timeUnit: "TIME_UNIT_HOUR").durationMinutes == 300)
        #expect(KimiWindow(duration: 7, timeUnit: "TIME_UNIT_DAY").durationMinutes == 10080)
        #expect(KimiWindow(duration: 0, timeUnit: "TIME_UNIT_HOUR").durationMinutes == nil)
        #expect(KimiWindow(duration: -1, timeUnit: "TIME_UNIT_DAY").durationMinutes == nil)
        #expect(KimiWindow(duration: Int.max, timeUnit: "TIME_UNIT_HOUR").durationMinutes == nil)
        #expect(KimiWindow(duration: 5, timeUnit: "TIME_UNIT_UNKNOWN").durationMinutes == nil)
    }

    @Test
    func `unknown rate window unit does not fabricate a duration`() throws {
        let json = """
        {
          "usage": {"limit": 1000, "used": 40, "remaining": 960},
          "limits": [
            {
              "window": {"duration": 5, "timeUnit": "TIME_UNIT_UNKNOWN"},
              "detail": {"limit": 100, "used": 25, "remaining": 75}
            }
          ]
        }
        """

        let usage = try KimiUsageFetcher._parseCodeAPIUsageForTesting(Data(json.utf8)).toUsageSnapshot()

        #expect(usage.secondary?.windowMinutes == nil)
        #expect(usage.secondary?.resetDescription == "Rate: 25/100")
    }

    @Test
    func `parses subscription stat response`() throws {
        let json = """
        {
          "ratelimitCode5h": {
            "ratio": 0.4689,
            "enabled": true,
            "resetTime": "2026-07-02T11:56:36.876796734Z"
          },
          "ratelimitCode7d": {
            "ratio": 0.0946,
            "enabled": true,
            "resetTime": "2026-07-09T06:56:36.876796734Z"
          },
          "subscriptionBalance": {
            "id": "19eee1de-9092-8315-8000-0000e4e34d79",
            "feature": "FEATURE_OMNI",
            "type": "SUBSCRIPTION",
            "unit": "UNIT_CREDIT",
            "amountUsedRatio": 1,
            "kimiCodeUsedRatio": 0.2854,
            "expireTime": "2026-07-23T00:00:00Z"
          },
          "giftBalances": [
            {
              "id": "19efdb95-e082-804c-9ecd-978b7ab37d36",
              "feature": "FEATURE_OMNI",
              "type": "GIFT",
              "unit": "UNIT_CREDIT",
              "amountUsedRatio": 1,
              "kimiCodeUsedRatio": 1,
              "expireTime": "2026-07-31T15:59:59Z"
            }
          ]
        }
        """

        let response = try JSONDecoder().decode(KimiSubscriptionStatsResponse.self, from: Data(json.utf8))

        #expect(response.subscriptionBalance?.feature == "FEATURE_OMNI")
        #expect(response.subscriptionBalance?.type == "SUBSCRIPTION")
        #expect(response.subscriptionBalance?.amountUsedRatio == 1)
        #expect(response.subscriptionBalance?.kimiCodeUsedRatio == 0.2854)
        #expect(response.subscriptionBalance?.expireTime == "2026-07-23T00:00:00Z")
        #expect(response.ratelimitCode7d?.ratio == 0.0946)
        #expect(response.ratelimitCode7d?.enabled == true)
        #expect(response.ratelimitCode7d?.resetTime == "2026-07-09T06:56:36.876796734Z")
    }

    @Test
    func `subscription grace is a total budget for existing usage windows`() async throws {
        let usageJSON = """
        {
          "usages": [
            {
              "scope": "FEATURE_CODING",
              "detail": { "limit": "100", "used": "25", "remaining": "75" },
              "limits": [
                {
                  "window": { "duration": 300, "timeUnit": "TIME_UNIT_MINUTE" },
                  "detail": { "limit": "20", "used": "5", "remaining": "15" }
                }
              ]
            }
          ]
        }
        """
        // Keep the cancellation-ignoring request slower than the scaled wall-clock guard.
        let subscriptionDelaySeconds = 0.5 * TestTimingBudget.slowdownFactor
        let transport = ProviderHTTPTransportHandler { request in
            let url = try #require(request.url)
            let response = try #require(HTTPURLResponse(
                url: url,
                statusCode: 200,
                httpVersion: nil,
                headerFields: nil))
            if url.path.hasSuffix("/GetUsages") {
                return await withCheckedContinuation { continuation in
                    DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
                        continuation.resume(returning: (Data(usageJSON.utf8), response))
                    }
                }
            }

            return await withCheckedContinuation { continuation in
                DispatchQueue.global().asyncAfter(deadline: .now() + subscriptionDelaySeconds) {
                    continuation.resume(returning: (Data("{}".utf8), response))
                }
            }
        }

        let startedAt = ContinuousClock.now
        let snapshot = try await KimiUsageFetcher._fetchUsageForTesting(
            authToken: "test-token",
            transport: transport,
            subscriptionGrace: .milliseconds(20))
        let elapsed = startedAt.duration(to: .now)
        let usage = snapshot.toUsageSnapshot()

        #expect(usage.primary?.usedPercent == 25)
        #expect(usage.primary?.windowMinutes == KimiProviderDescriptor.weeklyWindowMinutes)
        #expect(usage.secondary?.usedPercent == 25)
        #expect(usage.extraRateWindows == nil)
        #expect(
            elapsed < TestTimingBudget.scaled(.milliseconds(250)),
            "Subscription enrichment outlived its total budget: \(elapsed)")

        // Drain the deliberately cancellation-ignoring test request before the test exits.
        try await Task.sleep(for: TestTimingBudget.scaled(.milliseconds(550)))
    }

    @Test
    func `subscription stat enriches usage when it finishes within the total budget`() async throws {
        let usageJSON = """
        {
          "usages": [
            {
              "scope": "FEATURE_CODING",
              "detail": { "limit": "100", "used": "25", "remaining": "75" },
              "limits": []
            }
          ]
        }
        """
        let subscriptionJSON = """
        {
          "subscriptionBalance": {
            "feature": "FEATURE_OMNI",
            "type": "SUBSCRIPTION",
            "amountUsedRatio": 0.42,
            "expireTime": "2026-07-23T00:00:00Z"
          },
          "ratelimitCode7d": {
            "ratio": 0.17,
            "enabled": true,
            "resetTime": "2026-07-13T15:28:00Z"
          }
        }
        """
        let transport = ProviderHTTPTransportHandler { request in
            let url = try #require(request.url)
            let response = try #require(HTTPURLResponse(
                url: url,
                statusCode: 200,
                httpVersion: nil,
                headerFields: nil))
            if url.path.hasSuffix("/GetUsages") {
                return (Data(usageJSON.utf8), response)
            }
            #expect(url.path.hasSuffix("/GetSubscriptionStats"))
            return (Data(subscriptionJSON.utf8), response)
        }

        let snapshot = try await KimiUsageFetcher._fetchUsageForTesting(
            authToken: "test-token",
            transport: transport,
            subscriptionGrace: .seconds(1))
        let windows = try #require(snapshot.toUsageSnapshot().extraRateWindows)
        let monthly = try #require(windows.first { $0.id == "kimi-monthly" })
        let weeklyCode = try #require(windows.first { $0.id == "kimi-code-7d" })

        #expect(monthly.id == "kimi-monthly")
        #expect(monthly.window.usedPercent == 42)
        #expect(weeklyCode.title == "Code 7-day")
        #expect(weeklyCode.window.usedPercent == 17)
        #expect(weeklyCode.window.windowMinutes == 7 * 24 * 60)
    }

    @Test
    func `builds default code API usage endpoint`() throws {
        let baseURL = try #require(URL(string: "https://api.kimi.com"))
        let endpoint = KimiUsageFetcher._codeAPIUsageEndpointForTesting(baseURL: baseURL)

        #expect(endpoint.absoluteString == "https://api.kimi.com/coding/v1/usages")
    }

    @Test
    func `appends code API path to custom proxy root`() throws {
        let baseURL = try #require(URL(string: "https://proxy.example.com/kimi"))
        let endpoint = KimiUsageFetcher._codeAPIUsageEndpointForTesting(baseURL: baseURL)

        #expect(endpoint.absoluteString == "https://proxy.example.com/kimi/coding/v1/usages")
    }

    @Test
    func `does not duplicate code API path when base URL already includes it`() throws {
        let baseURL = try #require(URL(string: "https://api.kimi.com/coding/v1"))
        let endpoint = KimiUsageFetcher._codeAPIUsageEndpointForTesting(baseURL: baseURL)

        #expect(endpoint.absoluteString == "https://api.kimi.com/coding/v1/usages")
    }

    @Test
    func `does not duplicate code API path with trailing slash`() throws {
        let baseURL = try #require(URL(string: "https://proxy.example.com/kimi/coding/v1/"))
        let endpoint = KimiUsageFetcher._codeAPIUsageEndpointForTesting(baseURL: baseURL)

        #expect(endpoint.absoluteString == "https://proxy.example.com/kimi/coding/v1/usages")
    }

    @Test
    func `does not duplicate coding path prefix`() throws {
        let baseURL = try #require(URL(string: "https://proxy.example.com/kimi/coding/"))
        let endpoint = KimiUsageFetcher._codeAPIUsageEndpointForTesting(baseURL: baseURL)

        #expect(endpoint.absoluteString == "https://proxy.example.com/kimi/coding/v1/usages")
    }

    @Test
    func `rejects insecure code API base URL before sending bearer token`() async throws {
        let baseURL = try #require(URL(string: "http://proxy.example.com/kimi"))

        await #expect(throws: KimiAPIError.invalidRequest(
            "Kimi Code API base URL must use HTTPS without user info"))
        {
            _ = try await KimiUsageFetcher.fetchCodeAPIUsage(apiKey: "secret-token", baseURL: baseURL)
        }
    }

    @Test
    func `maps code API authentication and permission errors separately`() {
        #expect(KimiUsageFetcher._codeAPIErrorForTesting(statusCode: 401) == .invalidAPIKey)
        #expect(
            KimiUsageFetcher._codeAPIErrorForTesting(statusCode: 403)
                == .apiError("HTTP 403 (permission or quota denied)"))
    }

    @Test
    func `throws on invalid json`() {
        let invalidJson = "{ invalid json }"

        #expect(throws: DecodingError.self) {
            try JSONDecoder().decode(KimiUsageResponse.self, from: Data(invalidJson.utf8))
        }
    }

    @Test
    func `throws on missing feature coding scope`() throws {
        let json = """
        {
          "usages": [
            {
              "scope": "OTHER_SCOPE",
              "detail": {
                "limit": "100",
                "used": "50",
                "remaining": "50",
                "resetTime": "2026-01-09T15:23:13.373329235Z"
              }
            }
          ]
        }
        """

        let response = try JSONDecoder().decode(KimiUsageResponse.self, from: Data(json.utf8))
        let codingUsage = response.usages.first { $0.scope == "FEATURE_CODING" }
        #expect(codingUsage == nil)
    }
}

struct KimiUsageSnapshotConversionTests {
    @Test
    func `converts to usage snapshot with both windows`() throws {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        let rateLimitDetail = KimiUsageDetail(
            limit: "200",
            used: "200",
            remaining: "0",
            resetTime: "2026-01-06T15:05:24.374187075Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: rateLimitDetail,
            updatedAt: now)

        let usageSnapshot = snapshot.toUsageSnapshot()

        let primary = try #require(usageSnapshot.primary)
        let weeklyExpected = 375.0 / 2048.0 * 100.0
        #expect(abs(primary.usedPercent - weeklyExpected) < 0.01)
        #expect(primary.resetDescription == "375/2048 requests")
        #expect(primary.windowMinutes == KimiProviderDescriptor.weeklyWindowMinutes)
        #expect(KimiProviderDescriptor.descriptor.pace.supportsResetWindowPace(window: primary, now: now))

        let secondary = try #require(usageSnapshot.secondary)
        let rateExpected = 200.0 / 200.0 * 100.0
        #expect(abs(secondary.usedPercent - rateExpected) < 0.01)
        #expect(secondary.windowMinutes == KimiProviderDescriptor.sessionWindowMinutes)
        #expect(secondary.resetDescription == "Rate: 200/200 per 5 hours")
        #expect(!KimiProviderDescriptor.descriptor.pace.supportsResetWindowPace(window: secondary, now: now))

        #expect(usageSnapshot.tertiary == nil)
        #expect(usageSnapshot.updatedAt == now)
    }

    @Test
    func `converts subscription balance to monthly extra window`() throws {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        let subscriptionBalance = KimiSubscriptionBalance(
            feature: "FEATURE_OMNI",
            type: "SUBSCRIPTION",
            amountUsedRatio: 1,
            kimiCodeUsedRatio: nil,
            expireTime: "2026-07-23T00:00:00Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: subscriptionBalance,
            updatedAt: now)
        let usageSnapshot = snapshot.toUsageSnapshot()

        let monthly = try #require(usageSnapshot.extraRateWindows?.first)
        #expect(monthly.id == "kimi-monthly")
        #expect(monthly.title == "Total usage")
        #expect(monthly.window.usedPercent == 100)
        #expect(monthly.window.windowMinutes == ProviderPaceCapability.monthlyWindowSentinelMinutes)
        #expect(monthly.window.resetsAt == Self.date("2026-07-23T00:00:00Z"))
    }

    @Test
    func `reflects partial subscription usage in monthly window`() throws {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        // A live, partially-used balance (not the fully-exhausted 1.0 fixture): amountUsedRatio is a
        // real consumption ratio, so the Monthly window must track it rather than pin to 100%.
        let subscriptionBalance = KimiSubscriptionBalance(
            feature: "FEATURE_OMNI",
            type: "SUBSCRIPTION",
            amountUsedRatio: 0.7716,
            kimiCodeUsedRatio: nil,
            expireTime: "2026-07-23T00:00:00Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: subscriptionBalance,
            updatedAt: now)
        let usageSnapshot = snapshot.toUsageSnapshot()

        let monthly = try #require(usageSnapshot.extraRateWindows?.first)
        #expect(monthly.id == "kimi-monthly")
        #expect(abs(monthly.window.usedPercent - 77.16) < 0.0001)
    }

    @Test
    func `converts subscription code weekly limit to extra window`() throws {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        let subscriptionCodeWeeklyLimit = KimiSubscriptionRateLimit(
            ratio: 0.0946,
            enabled: true,
            resetTime: "2026-07-13T15:28:00Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: nil,
            subscriptionCodeWeeklyLimit: subscriptionCodeWeeklyLimit,
            updatedAt: now)
        let usageSnapshot = snapshot.toUsageSnapshot()

        let weeklyCode = try #require(usageSnapshot.extraRateWindows?.first)
        #expect(weeklyCode.id == "kimi-code-7d")
        #expect(weeklyCode.title == "Code 7-day")
        #expect(abs(weeklyCode.window.usedPercent - 9.46) < 0.0001)
        #expect(weeklyCode.window.windowMinutes == 7 * 24 * 60)
        #expect(weeklyCode.window.resetsAt == Self.date("2026-07-13T15:28:00Z"))
    }

    @Test
    func `hides code weekly window when it matches the primary weekly lane`() {
        // Live Kimi responses report the same 7-day Code quota from both GetUsages (FEATURE_CODING
        // detail) and GetSubscriptionStats (ratelimitCode7d); showing both rows duplicates one lane.
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "100",
            used: "29",
            remaining: "71",
            resetTime: "2026-08-13T17:02:44Z")
        let subscriptionCodeWeeklyLimit = KimiSubscriptionRateLimit(
            ratio: 0.2935,
            enabled: true,
            resetTime: "2026-08-13T17:02:43Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: nil,
            subscriptionCodeWeeklyLimit: subscriptionCodeWeeklyLimit,
            updatedAt: now)

        #expect(snapshot.toUsageSnapshot().extraRateWindows == nil)
    }

    @Test
    func `keeps code weekly window when the weekly detail is unreliable`() throws {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "100",
            used: nil,
            remaining: nil,
            resetTime: nil)
        let subscriptionCodeWeeklyLimit = KimiSubscriptionRateLimit(
            ratio: 0,
            enabled: true,
            resetTime: nil)

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: nil,
            subscriptionCodeWeeklyLimit: subscriptionCodeWeeklyLimit,
            updatedAt: now)
        let usageSnapshot = snapshot.toUsageSnapshot()
        let windows = try #require(usageSnapshot.extraRateWindows)

        // The numeric-limit fallback creates an unreliable 0% primary lane with no duration; it must
        // never suppress the subscription Code quota, which is the only reliable 7-day reading here.
        #expect(usageSnapshot.primary?.windowMinutes == nil)
        #expect(windows.map(\.id) == ["kimi-code-7d"])
    }

    @Test
    func `keeps code weekly window when neither lane reports a reset time`() throws {
        // Matching percentages alone cannot prove the lanes are the same quota: without reset
        // evidence on both sides, two independent quotas could coincide, so keep the Code row.
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "100",
            used: "29",
            remaining: "71",
            resetTime: nil)
        let subscriptionCodeWeeklyLimit = KimiSubscriptionRateLimit(
            ratio: 0.2935,
            enabled: true,
            resetTime: nil)

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            subscriptionBalance: nil,
            subscriptionCodeWeeklyLimit: subscriptionCodeWeeklyLimit,
            updatedAt: now)
        let windows = try #require(snapshot.toUsageSnapshot().extraRateWindows)

        #expect(windows.map(\.id) == ["kimi-code-7d"])
    }

    @Test
    func `omits disabled and nonfinite subscription quota ratios`() {
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        let invalidLimits = [
            KimiSubscriptionRateLimit(ratio: 0.25, enabled: false, resetTime: nil),
            KimiSubscriptionRateLimit(ratio: .nan, enabled: true, resetTime: nil),
            KimiSubscriptionRateLimit(ratio: .infinity, enabled: true, resetTime: nil),
        ]

        for limit in invalidLimits {
            let snapshot = KimiUsageSnapshot(
                weekly: weeklyDetail,
                rateLimit: nil,
                subscriptionBalance: KimiSubscriptionBalance(
                    feature: "FEATURE_OMNI",
                    type: "SUBSCRIPTION",
                    amountUsedRatio: .nan,
                    kimiCodeUsedRatio: nil,
                    expireTime: nil),
                subscriptionCodeWeeklyLimit: limit,
                updatedAt: Date())

            #expect(snapshot.toUsageSnapshot().extraRateWindows == nil)
        }
    }

    @Test
    func `converts to usage snapshot without rate limit`() {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            updatedAt: now)

        let usageSnapshot = snapshot.toUsageSnapshot()

        #expect(usageSnapshot.primary != nil)
        let weeklyExpected = 375.0 / 2048.0 * 100.0
        #expect(abs((usageSnapshot.primary?.usedPercent ?? 0.0) - weeklyExpected) < 0.01)
        #expect(usageSnapshot.secondary == nil)
        #expect(usageSnapshot.tertiary == nil)
    }

    @Test
    func `converts invalid rate limit as unavailable`() {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "375",
            remaining: "1673",
            resetTime: "2026-01-09T15:23:13.373329235Z")
        let invalidRateLimit = KimiUsageDetail(
            limit: "0",
            used: "0",
            remaining: "0",
            resetTime: "2026-01-06T15:05:24.374187075Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: invalidRateLimit,
            updatedAt: now)

        let usageSnapshot = snapshot.toUsageSnapshot()

        #expect(usageSnapshot.primary?.resetDescription == "375/2048 requests")
        #expect(usageSnapshot.secondary == nil)
    }

    @Test
    func `malformed limits do not fabricate pace metadata`() {
        let now = Date()
        let weekly = KimiUsageDetail(limit: "100", used: "25", remaining: "75", resetTime: nil)
        let invalid = KimiUsageDetail(limit: "invalid", used: "5", remaining: "15", resetTime: nil)
        let zero = KimiUsageDetail(limit: "0", used: "0", remaining: "0", resetTime: nil)

        #expect(KimiUsageSnapshot(weekly: invalid, rateLimit: nil, updatedAt: now).toUsageSnapshot().primary == nil)
        #expect(KimiUsageSnapshot(weekly: zero, rateLimit: nil, updatedAt: now).toUsageSnapshot().primary == nil)
        #expect(KimiUsageSnapshot(weekly: weekly, rateLimit: invalid, updatedAt: now)
            .toUsageSnapshot().secondary == nil)
    }

    @Test
    func `derives invalid or missing used counts from valid remaining counts`() throws {
        let now = Date()
        let snapshot = KimiUsageSnapshot(
            weekly: KimiUsageDetail(limit: "100", used: "invalid", remaining: "75", resetTime: nil),
            rateLimit: KimiUsageDetail(limit: "20", used: nil, remaining: "15", resetTime: nil),
            updatedAt: now)

        let usage = snapshot.toUsageSnapshot()
        #expect(try #require(usage.primary).usedPercent == 25)
        #expect(try #require(usage.secondary).usedPercent == 25)
    }

    @Test
    func `over quota used count wins over contradictory remaining`() throws {
        let now = Date()
        let snapshot = KimiUsageSnapshot(
            weekly: KimiUsageDetail(limit: "100", used: "125", remaining: "25", resetTime: nil),
            rateLimit: nil,
            updatedAt: now)

        let primary = try #require(snapshot.toUsageSnapshot().primary)
        #expect(primary.usedPercent == 100)
        #expect(primary.resetDescription == "125/100 requests")
        #expect(primary.windowMinutes == KimiProviderDescriptor.weeklyWindowMinutes)
    }

    @Test
    func `negative used count falls back to valid remaining`() throws {
        let now = Date()
        let snapshot = KimiUsageSnapshot(
            weekly: KimiUsageDetail(limit: "100", used: "-1", remaining: "75", resetTime: nil),
            rateLimit: nil,
            updatedAt: now)

        #expect(try #require(snapshot.toUsageSnapshot().primary).usedPercent == 25)
    }

    @Test
    func `invalid remaining does not synthesize a quota`() {
        let now = Date()
        for remaining in ["-1", "101", "invalid"] {
            let snapshot = KimiUsageSnapshot(
                weekly: KimiUsageDetail(limit: "100", used: nil, remaining: remaining, resetTime: nil),
                rateLimit: nil,
                updatedAt: now)

            #expect(snapshot.toUsageSnapshot().primary?.usedPercent == 0)
            #expect(snapshot.toUsageSnapshot().primary?.windowMinutes == nil)
        }
    }

    @Test
    func `missing counters preserve gauge without pace metadata`() throws {
        let snapshot = KimiUsageSnapshot(
            weekly: KimiUsageDetail(limit: "100", used: nil, remaining: nil, resetTime: nil),
            rateLimit: nil,
            updatedAt: Date())

        let primary = try #require(snapshot.toUsageSnapshot().primary)
        #expect(primary.usedPercent == 0)
        #expect(primary.windowMinutes == nil)
        #expect(primary.resetDescription == "0/100 requests")
    }

    @Test
    func `handles zero values correctly`() {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "0",
            remaining: "2048",
            resetTime: "2026-01-09T15:23:13.373329235Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            updatedAt: now)

        let usageSnapshot = snapshot.toUsageSnapshot()
        #expect(usageSnapshot.primary?.usedPercent == 0.0)
        #expect(usageSnapshot.secondary == nil)
    }

    @Test
    func `handles hundred percent correctly`() {
        let now = Date()
        let weeklyDetail = KimiUsageDetail(
            limit: "2048",
            used: "2048",
            remaining: "0",
            resetTime: "2026-01-09T15:23:13.373329235Z")

        let snapshot = KimiUsageSnapshot(
            weekly: weeklyDetail,
            rateLimit: nil,
            updatedAt: now)

        let usageSnapshot = snapshot.toUsageSnapshot()
        #expect(usageSnapshot.primary?.usedPercent == 100.0)
        #expect(usageSnapshot.secondary == nil)
    }

    private static func date(_ text: String) -> Date? {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime]
        return formatter.date(from: text)
    }
}

struct KimiTokenResolverTests {
    @Test
    func `resolves token from environment`() {
        KeychainAccessGate.withTaskOverrideForTesting(true) {
            let env = ["KIMI_AUTH_TOKEN": "test.jwt.token"]
            let token = ProviderTokenResolver.token(for: .kimi, environment: env)
            #expect(token == "test.jwt.token")
        }
    }

    @Test
    func `resolves token from keychain first`() {
        // This test would require mocking the keychain.
        KeychainAccessGate.withTaskOverrideForTesting(true) {
            let env = ["KIMI_AUTH_TOKEN": "test.env.token"]
            let token = ProviderTokenResolver.token(for: .kimi, environment: env)
            #expect(token == "test.env.token")
        }
    }

    @Test
    func `resolution includes source`() {
        KeychainAccessGate.withTaskOverrideForTesting(true) {
            let env = ["KIMI_AUTH_TOKEN": "test.jwt.token"]
            let resolution = ProviderTokenResolver.resolution(for: .kimi, environment: env)

            #expect(resolution?.token == "test.jwt.token")
            #expect(resolution?.source == .environment)
        }
    }
}

struct KimiAPIErrorTests {
    @Test
    func `error descriptions are helpful`() {
        #expect(KimiAPIError.missingToken.errorDescription?.contains("missing") == true)
        #expect(KimiAPIError.invalidToken.errorDescription?.contains("invalid") == true)
        #expect(KimiAPIError.missingAPIKey.errorDescription?.contains("Settings > Providers > Kimi") == true)
        #expect(KimiAPIError.missingAPIKey.errorDescription?.contains("KIMI_CODE_API_KEY") == true)
        #expect(KimiAPIError.expiredCodeCredential.errorDescription?.contains("does not refresh") == true)
        #expect(KimiAPIError.invalidCodeCredential.errorDescription?.contains("Sign in again") == true)
        #expect(KimiAPIError.invalidAPIKey.errorDescription?.contains("API key") == true)
        #expect(KimiAPIError.invalidRequest("Bad request").errorDescription?.contains("Bad request") == true)
        #expect(KimiAPIError.networkError("Timeout").errorDescription?.contains("Timeout") == true)
        #expect(KimiAPIError.apiError("HTTP 500").errorDescription?.contains("HTTP 500") == true)
        #expect(KimiAPIError.parseFailed("Invalid JSON").errorDescription?.contains("Invalid JSON") == true)
    }
}
