import { afterEach, describe, expect, it, vi } from "vitest";

import {
  apiFetch,
  getApiSession,
  loginApiSession,
  logoutApiSession,
} from "../api-client";

describe("case API session client", () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it("checks browser session state with same-origin credentials", async () => {
    vi.stubGlobal(
      "fetch",
      vi.fn(async () => jsonResponse({ authenticated: true })),
    );

    await expect(getApiSession()).resolves.toEqual({ authenticated: true });
    expect(fetch).toHaveBeenCalledWith("/api/auth/session", {
      credentials: "same-origin",
    });
  });

  it("creates a browser session with the provided access key", async () => {
    vi.stubGlobal(
      "fetch",
      vi.fn(async () => jsonResponse({ authenticated: true })),
    );

    await expect(loginApiSession("local-dev-key")).resolves.toEqual({
      authenticated: true,
    });
    expect(fetch).toHaveBeenCalledWith("/api/auth/session", {
      method: "POST",
      credentials: "same-origin",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ api_access_key: "local-dev-key" }),
    });
  });

  it("surfaces login errors from the session endpoint", async () => {
    vi.stubGlobal(
      "fetch",
      vi.fn(async () => jsonResponse({ error: "Unauthorized" }, 401)),
    );

    await expect(loginApiSession("wrong")).resolves.toEqual({
      authenticated: false,
      error: "Unauthorized",
    });
  });

  it("clears the browser session", async () => {
    vi.stubGlobal(
      "fetch",
      vi.fn(async () => jsonResponse({ authenticated: false })),
    );

    await expect(logoutApiSession()).resolves.toEqual({ authenticated: false });
    expect(fetch).toHaveBeenCalledWith("/api/auth/session", {
      method: "DELETE",
      credentials: "same-origin",
    });
  });

  it("adds same-origin credentials to protected API requests", async () => {
    vi.stubGlobal("fetch", vi.fn(async () => jsonResponse({ ok: true })));

    await apiFetch("/api/cases", { headers: { accept: "application/json" } });

    expect(fetch).toHaveBeenCalledWith("/api/cases", {
      credentials: "same-origin",
      headers: { accept: "application/json" },
    });
  });
});

function jsonResponse(body: unknown, status = 200) {
  return new Response(JSON.stringify(body), {
    status,
    headers: { "content-type": "application/json" },
  });
}
