import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import Testing
@testable import CodexBarCore

private final class MistralRequestCapture: @unchecked Sendable {
    private let lock = NSLock()
    private var storedRequest: URLRequest?

    var request: URLRequest? {
        self.lock.withLock { self.storedRequest }
    }

    func record(_ request: URLRequest) {
        self.lock.withLock { self.storedRequest = request }
    }
}

private final class MistralRequestPathLog: @unchecked Sendable {
    private let lock = NSLock()
    private var storedPaths: [String] = []

    var paths: [String] {
        self.lock.withLock { self.storedPaths }
    }

    func record(_ request: URLRequest) {
        let host = request.url?.host ?? ""
        let path = request.url?.path ?? ""
        self.lock.withLock {
            self.storedPaths.append("\(host)\(path)")
        }
    }
}

private final class MistralCookieHeaderLog: @unchecked Sendable {
    private let lock = NSLock()
    private var storedHeaders: [String] = []

    var headers: [String] {
        self.lock.withLock { self.storedHeaders }
    }

    func record(_ request: URLRequest) {
        self.lock.withLock {
            self.storedHeaders.append(request.value(forHTTPHeaderField: "Cookie") ?? "")
        }
    }
}

struct MistralVibeUsageTests {
    #if os(macOS)
    @Test
    func `cookie importer uses only accepted Mistral domains`() {
        #expect(Set(MistralCookieImporter.cookieDomains) == [
            "mistral.ai",
            "admin.mistral.ai",
            "auth.mistral.ai",
            "console.mistral.ai",
        ])

        let referenceDate = Date(timeIntervalSince1970: 1_700_000_000)
        let query = MistralCookieImporter.cookieQuery(referenceDate: referenceDate)
        #expect(query.domains == MistralCookieImporter.cookieDomains)
        #expect(query.includeExpired == false)
        #expect(query.referenceDate == referenceDate)
        guard case .exact = query.domainMatch else {
            Issue.record("Expected exact Mistral cookie-domain matching")
            return
        }
    }

    @Test
    func `tries later browser sessions after invalid credentials`() async throws {
        let headerLog = MistralCookieHeaderLog()
        let usageData = Data(Self.billingUsageResponseJSON.utf8)
        let sessions = try [
            Self.session(cookieName: "ory_session_chrome", value: "stale", sourceLabel: "Chrome"),
            Self.session(cookieName: "ory_session_firefox", value: "stale", sourceLabel: "Firefox"),
            Self.session(cookieName: "ory_session_safari", value: "valid", sourceLabel: "Safari"),
        ]
        let transport = ProviderHTTPTransportHandler { request in
            guard let url = request.url else { throw URLError(.badURL) }
            if url.host == "admin.mistral.ai", url.path == "/api/billing/v2/usage" {
                headerLog.record(request)
                let cookieHeader = request.value(forHTTPHeaderField: "Cookie") ?? ""
                let statusCode = cookieHeader.contains("ory_session_safari=valid") ? 200 : 401
                return try (usageData, Self.response(url: url, statusCode: statusCode))
            }
            return try (Data(), Self.response(url: url, statusCode: 404))
        }

        let (_, session) = try await MistralWebFetchStrategy.fetchUsageFromSessions(
            sessions,
            timeout: 2,
            transport: transport)

        #expect(session.sourceLabel == "Safari")
        #expect(headerLog.headers == [
            "ory_session_chrome=stale",
            "ory_session_firefox=stale",
            "ory_session_safari=valid",
        ])
    }
    #endif

    @Test
    func `parses subscription percentage and reset`() throws {
        let data = Data(Self.responseJSON(usagePercentage: 2.8141356666666666).utf8)

        let result = try MistralUsageFetcher.parseVibeUsage(data: data)

        #expect(result.usagePercentage == 2.8141356666666666)
        #expect(result.resetAt == ISO8601DateFormatter().date(from: "2026-07-01T00:00:00Z"))
    }

    @Test
    func `rejects subscription percentages outside rate window range`() {
        let data = Data(Self.responseJSON(usagePercentage: 101).utf8)

        #expect(throws: MistralUsageError.self) {
            try MistralUsageFetcher.parseVibeUsage(data: data)
        }
    }

    @Test
    func `subscription request sends only csrf cookie`() async throws {
        let capture = MistralRequestCapture()
        let data = Data(Self.responseJSON(usagePercentage: 12.5).utf8)
        let transport = ProviderHTTPTransportHandler { request in
            capture.record(request)
            guard let url = request.url,
                  let response = HTTPURLResponse(
                      url: url,
                      statusCode: 200,
                      httpVersion: nil,
                      headerFields: nil)
            else {
                throw URLError(.badURL)
            }
            return (data, response)
        }

        let result = try await MistralUsageFetcher.fetchVibeUsage(
            csrfToken: " csrf-value ",
            timeout: 2,
            transport: transport)
        let request = try #require(capture.request)

        #expect(result.usagePercentage == 12.5)
        #expect(request.url?.host == "console.mistral.ai")
        #expect(request.timeoutInterval == 2)
        #expect(request.httpShouldHandleCookies == false)
        #expect(request.value(forHTTPHeaderField: "Cookie") == "csrftoken=csrf-value")
        #expect(request.value(forHTTPHeaderField: "X-CSRFToken") == "csrf-value")
        #expect(request.allHTTPHeaderFields?.values.contains { $0.contains("ory_session") } != true)
    }

    @Test
    func `rejects csrf values that could add cookies or headers`() {
        #expect(throws: MistralUsageError.self) {
            try MistralUsageFetcher.vibeCookieHeader(csrfToken: "csrf; ory_session_secret=leak")
        }
        #expect(throws: MistralUsageError.self) {
            try MistralUsageFetcher.vibeCookieHeader(csrfToken: "csrf\r\nX-Leak: value")
        }
    }

    @Test
    func `optional subscription request propagates in flight cancellation`() async throws {
        let started = AsyncStream<Void>.makeStream(of: Void.self)
        let transport = ProviderHTTPTransportHandler { _ in
            started.continuation.yield(())
            try await Task.sleep(for: .seconds(30))
            throw URLError(.timedOut)
        }
        let task = Task {
            try await MistralWebFetchStrategy.fetchOptionalVibeUsage(
                csrfToken: "csrf-value",
                timeout: 30,
                transport: transport)
        }

        var iterator = started.stream.makeAsyncIterator()
        _ = await iterator.next()
        task.cancel()

        await #expect(throws: CancellationError.self) {
            try await task.value
        }
        started.continuation.finish()
    }

    @Test
    func `optional subscription request ignores ordinary endpoint failures`() async throws {
        let transport = ProviderHTTPTransportHandler { _ in
            throw URLError(.cannotConnectToHost)
        }

        let result = try await MistralWebFetchStrategy.fetchOptionalVibeUsage(
            csrfToken: "csrf-value",
            timeout: 2,
            transport: transport)

        #expect(result == nil)
    }

    @Test
    func `combined fetch preserves monthly plan when optional credits time out`() async throws {
        let requestLog = MistralRequestPathLog()
        let usageData = Data(Self.billingUsageResponseJSON.utf8)
        let vibeData = Data(Self.responseJSON(usagePercentage: 37).utf8)
        let transport = ProviderHTTPTransportHandler { request in
            requestLog.record(request)
            guard let url = request.url else { throw URLError(.badURL) }
            if url.host == "admin.mistral.ai", url.path == "/api/billing/v2/usage" {
                let response = try Self.response(url: url, statusCode: 200)
                return (usageData, response)
            }
            if url.host == "console.mistral.ai" {
                let response = try Self.response(url: url, statusCode: 200)
                return (vibeData, response)
            }
            if url.host == "admin.mistral.ai", url.path == "/api/billing/credits" {
                try await Task.sleep(for: .milliseconds(25))
                throw URLError(.timedOut)
            }
            throw URLError(.badURL)
        }

        let snapshot = try await MistralWebFetchStrategy.fetchUsageWithVibe(
            cookieHeader: "ory_session_test=abc; csrftoken=csrf",
            csrfToken: "csrf",
            timeout: 1,
            transport: transport)

        let monthlyPlan = snapshot.extraRateWindows?.first { $0.id == "mistral-monthly-plan" }
        #expect(monthlyPlan?.window.usedPercent == 37)
        #expect(snapshot.mistralUsage?.credits == nil)
        #expect(requestLog.paths == [
            "admin.mistral.ai/api/billing/v2/usage",
            "console.mistral.ai/api-ui/trpc/billing.vibeUsage",
            "admin.mistral.ai/api/billing/credits",
        ])
    }

    @Test
    func `monthly plan window preserves existing extras`() {
        let existing = NamedRateWindow(
            id: "existing",
            title: "Existing",
            window: RateWindow(usedPercent: 5, windowMinutes: nil, resetsAt: nil, resetDescription: nil))
        let usage = UsageSnapshot(
            primary: nil,
            secondary: nil,
            extraRateWindows: [existing],
            updatedAt: Date())

        let updated = MistralWebFetchStrategy.attachVibeWindow(
            to: usage,
            vibeResult: .init(usagePercentage: 25, resetAt: nil))

        #expect(updated.extraRateWindows?.map(\.id) == ["existing", "mistral-monthly-plan"])
        #expect(updated.extraRateWindows?.last?.window.usedPercent == 25)
    }

    // MARK: - consoleCookieHeader allowlist

    @Test
    func `console cookie header contains only csrf when no admin header`() {
        let cookie = MistralUsageFetcher.consoleCookieHeader(csrfToken: "tok", adminCookieHeader: nil)
        #expect(cookie == "csrftoken=tok")
    }

    @Test
    func `console cookie header forwards ory session alongside csrf`() {
        let admin = "csrftoken=tok; ory_session_coolcurranf83m3srkfl=sess123; other_admin=secret"
        let cookie = MistralUsageFetcher.consoleCookieHeader(csrfToken: "tok", adminCookieHeader: admin)
        #expect(cookie == "csrftoken=tok; ory_session_coolcurranf83m3srkfl=sess123")
    }

    @Test
    func `console cookie header excludes non-session admin cookies`() {
        let admin = "csrftoken=tok; session_token=other; admin_secret=x"
        let cookie = MistralUsageFetcher.consoleCookieHeader(csrfToken: "tok", adminCookieHeader: admin)
        #expect(cookie == "csrftoken=tok")
        #expect(!cookie.contains("admin_secret"))
        #expect(!cookie.contains("session_token"))
    }

    @Test
    func `console cookie header forwards multiple ory session cookies`() {
        let admin = "ory_session_a=val1; ory_session_b=val2; unrelated=drop"
        let cookie = MistralUsageFetcher.consoleCookieHeader(csrfToken: "tok", adminCookieHeader: admin)
        #expect(cookie.contains("csrftoken=tok"))
        #expect(cookie.contains("ory_session_a=val1"))
        #expect(cookie.contains("ory_session_b=val2"))
        #expect(!cookie.contains("unrelated"))
    }

    private static func responseJSON(usagePercentage: Double) -> String {
        """
        [{"result":{"data":{"json":{
          "usage_percentage":\(usagePercentage),
          "quota_changed_this_month":false,
          "payg_enabled":false,
          "reset_at":"2026-07-01T00:00:00Z"
        }}}}]
        """
    }

    #if os(macOS)
    private static func session(cookieName: String, value: String, sourceLabel: String) throws
        -> MistralCookieImporter.SessionInfo
    {
        let cookie = try #require(HTTPCookie(properties: [
            .domain: "admin.mistral.ai",
            .path: "/",
            .name: cookieName,
            .value: value,
        ]))
        return MistralCookieImporter.SessionInfo(cookies: [cookie], sourceLabel: sourceLabel)
    }
    #endif

    private static var billingUsageResponseJSON: String {
        """
        {
          "completion": {"models": {}},
          "ocr": {"models": {}},
          "connectors": {"models": {}},
          "libraries_api": {"pages": {"models": {}}, "tokens": {"models": {}}},
          "fine_tuning": {"training": {}, "storage": {}},
          "audio": {"models": {}},
          "vibe_usage": 0.0,
          "date": "2026-02-01T00:00:00Z",
          "previous_month": "2026-01",
          "next_month": "2026-03",
          "start_date": "2026-02-01T00:00:00Z",
          "end_date": "2026-02-28T23:59:59.999Z",
          "currency": "USD",
          "currency_symbol": "$",
          "prices": []
        }
        """
    }

    private static func response(url: URL, statusCode: Int) throws -> HTTPURLResponse {
        try #require(HTTPURLResponse(
            url: url,
            statusCode: statusCode,
            httpVersion: nil,
            headerFields: nil))
    }
}
