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

import { unsubscribeAlertRecipient } from "./unsubscribe-alert-recipient";

const fetchMock = vi.fn();

const lastFetchCall = (): { url: string; init: RequestInit } => {
  const call = fetchMock.mock.calls.at(-1);
  if (!call) throw new Error("fetch was not called");
  const [url, init] = call;
  return { url: String(url), init: (init ?? {}) as RequestInit };
};

describe("unsubscribeAlertRecipient", () => {
  beforeEach(() => {
    vi.stubGlobal("fetch", fetchMock);
    vi.stubEnv("NEXT_PUBLIC_API_BASE_URL", "https://api.example.com/api/v1");
    fetchMock.mockResolvedValue(
      new Response(
        JSON.stringify({
          state: "unsubscribed",
          message:
            "You have been unsubscribed. You will not receive further alerts at this address.",
        }),
        { status: 200, headers: { "Content-Type": "application/json" } },
      ),
    );
  });

  afterEach(() => {
    vi.unstubAllEnvs();
    vi.unstubAllGlobals();
    vi.clearAllMocks();
  });

  it("calls the public unsubscribe endpoint without auth headers", async () => {
    // When
    const result = await unsubscribeAlertRecipient("token-1");

    // Then
    expect(result).toEqual({
      ok: true,
      state: "unsubscribed",
      message:
        "You have been unsubscribed. You will not receive further alerts at this address.",
    });
    const { url, init } = lastFetchCall();
    expect(url).toBe(
      "https://api.example.com/api/v1/alerts/recipients/unsubscribe?token=token-1",
    );
    expect(init).toEqual({
      headers: { Accept: "application/json" },
      cache: "no-store",
    });
  });

  it("returns the API message for invalid tokens", async () => {
    // Given
    fetchMock.mockResolvedValueOnce(
      new Response(
        JSON.stringify({
          state: "invalid_token",
          message: "This link is invalid or has expired.",
        }),
        { status: 400, headers: { "Content-Type": "application/json" } },
      ),
    );

    // When
    const result = await unsubscribeAlertRecipient("expired-token");

    // Then
    expect(result).toEqual({
      ok: false,
      state: "invalid_token",
      message: "This link is invalid or has expired.",
    });
  });

  it("returns the API message for missing tokens", async () => {
    // Given
    fetchMock.mockResolvedValueOnce(
      new Response(
        JSON.stringify({
          state: "missing_token",
          message: "This link is missing a token.",
        }),
        { status: 400, headers: { "Content-Type": "application/json" } },
      ),
    );

    // When
    const result = await unsubscribeAlertRecipient();

    // Then
    expect(result).toEqual({
      ok: false,
      state: "missing_token",
      message: "This link is missing a token.",
    });
    expect(lastFetchCall().url).toBe(
      "https://api.example.com/api/v1/alerts/recipients/unsubscribe",
    );
  });
});
