import { describe, expect, mock, test } from "bun:test";

mock.module("server-only", () => ({}));
const resolveSiteGscToken = mock(async (siteId: string) =>
  siteId === "ok-site"
    ? {
        ok: true as const,
        accessToken: "tok",
        property: "sc-domain:x.com",
        // Champs internes : la route ne doit PAS les recopier dans le 200.
        authorityUserId: "u1",
        authorityAccountId: "g1",
      }
    : { ok: false as const, reason: "no-authority" as const },
);
mock.module("@/lib/gsc/site-token", () => ({ resolveSiteGscToken }));
const envObj = { WORKER_API_KEY: "secret-key" as string | undefined };
mock.module("@/env", () => ({ env: envObj }));

const { POST } = await import("@/app/api/worker/gsc-token/route");

const req = (auth: string | null, body: unknown) =>
  new Request("http://test/api/worker/gsc-token", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(auth ? { Authorization: auth } : {}),
    },
    body: JSON.stringify(body),
  });

describe("POST /api/worker/gsc-token", () => {
  test("401 without / with wrong bearer", async () => {
    expect((await POST(req(null, { siteId: "ok-site" }))).status).toBe(401);
    expect((await POST(req("Bearer nope", { siteId: "ok-site" }))).status).toBe(
      401,
    );
  });

  test("200 with token for a resolvable site", async () => {
    const res = await POST(req("Bearer secret-key", { siteId: "ok-site" }));
    expect(res.status).toBe(200);
    expect(await res.json()).toEqual({
      accessToken: "tok",
      property: "sc-domain:x.com",
    });
  });

  test("404 when unresolvable; 400 on missing siteId", async () => {
    expect(
      (await POST(req("Bearer secret-key", { siteId: "ghost" }))).status,
    ).toBe(404);
    expect((await POST(req("Bearer secret-key", {}))).status).toBe(400);
  });

  test("404 avec la raison quand le site n'est pas résoluble", async () => {
    const res = await POST(req("Bearer secret-key", { siteId: "ko" }));
    expect(res.status).toBe(404);
    expect(await res.json()).toEqual({
      error: "not resolvable",
      reason: "no-authority",
    });
  });

  // Le worker Rust jette le corps des 4xx : sans ce log côté Next, la raison
  // n'existe nulle part (incident prod du 2026-07-02). Verrouillé par un test
  // parce que c'est précisément le genre de ligne qu'un refactor supprime.
  test("journalise la raison du 404 côté serveur", async () => {
    const original = console.error;
    const calls: unknown[][] = [];
    console.error = (...args: unknown[]) => {
      calls.push(args);
    };
    try {
      await POST(req("Bearer secret-key", { siteId: "ko" }));
    } finally {
      console.error = original;
    }
    expect(calls).toHaveLength(1);
    expect(calls[0][0]).toBe("[gsc-broker] site non résolvable");
    expect(calls[0][1]).toEqual({ siteId: "ko", reason: "no-authority" });
  });

  // LAST: mutates the shared env mock (WORKER_API_KEY unset → 503).
  test("503 when WORKER_API_KEY is not configured", async () => {
    envObj.WORKER_API_KEY = undefined;
    expect(
      (await POST(req("Bearer secret-key", { siteId: "ok-site" }))).status,
    ).toBe(503);
  });
});
