import Foundation
import Testing

@testable import NucleicCore

struct ClaudeCredentialBrokerTests {
    private static func login(
        expiresAt: Double,
        refreshToken: String = "refresh",
        scopesJSON: String = #"["user:profile","user:inference"]"#
    ) -> String {
        """
        {"claudeAiOauth":{"accessToken":"access","refreshToken":"\(refreshToken)",        "expiresAt":\(Int(expiresAt)),"scopes":\(scopesJSON)}}
        """
    }

    @Test func parsesRefreshTokenArrayScopesAndExpiry() {
        let json = Self.login(expiresAt: 1_700_000_000_000)
        #expect(ClaudeCredentialBroker.refreshMaterial(from: json) == .init(
            refreshToken: "refresh",
            scopes: ["user:profile", "user:inference"],
            expiresAt: 1_700_000_000_000))
    }

    @Test func parsesSpaceSeparatedScopes() {
        let json = Self.login(
            expiresAt: 1_700_000_000_000,
            scopesJSON: #""user:profile user:inference user:sessions:claude_code""#)
        #expect(ClaudeCredentialBroker.refreshMaterial(from: json)?.scopes == [
            "user:profile", "user:inference", "user:sessions:claude_code",
        ])
    }

    @Test func rejectsIncompleteRefreshMetadata() {
        #expect(ClaudeCredentialBroker.refreshMaterial(
            from: Self.login(expiresAt: 1_000, refreshToken: "")) == nil)
        #expect(ClaudeCredentialBroker.refreshMaterial(
            from: Self.login(expiresAt: 1_000, scopesJSON: "[]")) == nil)
        #expect(ClaudeCredentialBroker.refreshMaterial(
            from: #"{"claudeAiOauth":{"accessToken":"a","refreshToken":"r","scopes":["s"]}}"#) == nil)
        #expect(ClaudeCredentialBroker.refreshMaterial(from: "not json") == nil)
    }

    @Test func refreshesAtThirtyMinuteBoundary() {
        let now = Date(timeIntervalSince1970: 1_700_000_000)
        let twentyNineMinutes = (now.timeIntervalSince1970 + 29 * 60) * 1_000
        let thirtyMinutes = (now.timeIntervalSince1970 + 30 * 60) * 1_000
        let thirtyOneMinutes = (now.timeIntervalSince1970 + 31 * 60) * 1_000

        #expect(ClaudeCredentialBroker.needsRefresh(expiresAt: twentyNineMinutes, now: now))
        #expect(ClaudeCredentialBroker.needsRefresh(expiresAt: thirtyMinutes, now: now))
        #expect(!ClaudeCredentialBroker.needsRefresh(expiresAt: thirtyOneMinutes, now: now))
    }

    @Test func customLeewayIsHonored() {
        let now = Date(timeIntervalSince1970: 1_700_000_000)
        let expiry = (now.timeIntervalSince1970 + 20) * 1_000
        #expect(!ClaudeCredentialBroker.needsRefresh(
            expiresAt: expiry, now: now, leeway: 10))
        #expect(ClaudeCredentialBroker.needsRefresh(
            expiresAt: expiry, now: now, leeway: 30))
    }
}
