import Foundation
import Testing
@testable import IrdAPI
@Suite struct DeviceLoginTests {
let start = json(200, #"{"device_code":"dc","user_code":"ABCD-1234","verification_uri":"https://ird.ro/device","verification_uri_complete":"https://ird.ro/device?code=ABCD-1234","expires_in":600,"interval":5}"#)
let complete = json(200, #"{"access_token":"eyJ.access","refresh_token":"rt","user":{"id":"u1","email":"a@b.ro","created_at":"2026-01-01T00:00:00Z"}}"#)
@Test func loginPollsThroughPendingAndSlowDownThenCompletes() async throws {
let (client, http) = captureClient(script: [
start,
json(400, #"{"error":{"code":"authorization-pending","message":"not yet"}}"#),
json(429, #"{"error":{"code":"slow-down","message":"slow"}}"#),
json(200, #"{"approved":false}"#),
json(200, #"{"approved":true}"#),
complete,
])
let clock = TestClock()
var c = client.configuration
c.clock = clock
let clocked = IrdClient(configuration: c)
let task = Task { try await clocked.auth.deviceLogin(prompt: { _ in }, confirmationCode: { s in s.userCode == "ABCD-1234" ? "CONF-99" : "?" }) }
for _ in 0..<3 {
#expect(await eventually { clock.sleeperCount == 1 })
clock.advance(by: .seconds(40))
}
let session = try await task.value
#expect(session.accessToken == "eyJ.access")
#expect(session.user.email == "a@b.ro")
#expect(http.trail == ["POST /auth/device/start", "POST /auth/device/poll", "POST /auth/device/poll", "POST /auth/device/poll", "POST /auth/device/poll", "POST /auth/device/complete"])
#expect(bodyJSON(http.requests[1]) == ["device_code": "dc"])
#expect(bodyJSON(http.requests[5]) == ["device_code": "dc", "confirmation_code": "CONF-99"])
#expect(clock.recordedSleeps == [.seconds(5), .seconds(10), .seconds(20)])
for r in http.requests { #expect(r.value(forHTTPHeaderField: "Authorization") == nil, "device flow never sends the bearer") }
}
@Test func otherErrorsWhilePollingAreRethrown() async throws {
let (client, _) = captureClient(script: [start, json(403, #"{"error":{"code":"expired","message":"gone"}}"#)])
let e = await caught { _ = try await client.auth.deviceLogin(prompt: { _ in }, confirmationCode: { _ in "x" }) }
#expect(e?.status == 403)
}
@Test func phasesCanBeDrivenSeparately() async throws {
let (client, http) = captureClient(script: [start, json(200, #"{"approved":true}"#), complete])
let s = try await client.auth.startDeviceLogin()
#expect(s.verificationUriComplete == "https://ird.ro/device?code=ABCD-1234")
try await client.auth.waitForDeviceApproval(s, interval: .milliseconds(1), timeout: .seconds(1))
let done = try await client.auth.completeDeviceLogin(s, confirmationCode: "CONF-1")
#expect(done.refreshToken == "rt")
#expect(http.count == 3)
}
}