import test from "node:test"
import assert from "node:assert/strict"
import { redactRequestOptionsForLog } from "../../lib/api-request-log"

const loadApiClient = () => import(new URL("../../lib/api-client.ts", import.meta.url).href)

test("ApiClient does not mutate request options and preserves existing query parameters", async () => {
  const { ApiClient } = await loadApiClient()
  const urls: string[] = []
  const transport = {
    fetch: async (input: string | Request) => {
      urls.push(String(input))
      return Response.json({ ok: true })
    },
  }
  const client = new ApiClient(transport, { baseUrl: "https://console.test/api" })
  const options = { params: { page: "2" }, headers: { "X-Request": "one" } }

  await client.get("/objects?prefix=photos", options)
  await client.get("/objects?prefix=photos", options)

  assert.deepEqual(options, { params: { page: "2" }, headers: { "X-Request": "one" } })
  assert.deepEqual(urls, [
    "https://console.test/api/objects?prefix=photos&page=2",
    "https://console.test/api/objects?prefix=photos&page=2",
  ])
})

test("ApiClient rejects 401 and 403 responses after invoking global handlers", async () => {
  const { ApiClient } = await loadApiClient()
  const handled: number[] = []
  const errorHandler = {
    handle401: async () => {
      handled.push(401)
    },
    handle403: async () => {
      handled.push(403)
    },
    handleServerError: async () => {},
    handleByStatus: async () => {},
  }
  const statuses = [401, 403]
  const client = new ApiClient(
    {
      fetch: async () => {
        const status = statuses.shift() ?? 500
        return Response.json({ message: `HTTP ${status}` }, { status })
      },
    },
    { errorHandler },
  )

  await assert.rejects(client.get("https://console.test/unauthorized"), { message: "HTTP 401", status: 401 })
  await assert.rejects(client.get("https://console.test/forbidden"), { message: "HTTP 403", status: 403 })
  assert.deepEqual(handled, [401, 403])
})

test("ApiClient preserves an explicitly resolved same-origin admin path", async () => {
  const { ApiClient } = await loadApiClient()
  const urls: string[] = []
  const client = new ApiClient(
    {
      fetch: async (input: string | Request) => {
        urls.push(String(input))
        return Response.json({ ok: true })
      },
    },
    { baseUrl: "https://console.test/rustfs/admin/v3" },
  )

  await client.get(client.resolveUrl("/rustfs/admin/v4/cluster/snapshot"))

  assert.deepEqual(urls, ["https://console.test/rustfs/admin/v4/cluster/snapshot"])
})

test("ApiClient redacts sensitive headers and request bodies from development logs", () => {
  const redacted = redactRequestOptionsForLog({
    headers: { Authorization: "Bearer header-secret", Cookie: "session=cookie-secret" },
    body: JSON.stringify({
      password: "body-secret",
      secretKey: "tier-secret-key",
      profile: { apiKey: "nested-secret" },
      creds: '{"private_key":"gcs-private-key"}',
    }),
  })

  const serialized = JSON.stringify(redacted)
  assert.doesNotMatch(
    serialized,
    /body-secret|tier-secret-key|nested-secret|header-secret|cookie-secret|gcs-private-key/,
  )
  assert.match(serialized, /\[REDACTED\]/)
})
