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

const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);

vi.mock("expo-constants", () => ({
  default: {
    expoConfig: {
      extra: { apiBaseUrl: "http://test.example" },
    },
  },
}));

vi.mock("../src/lib/auth", () => ({
  useAuth: {
    getState: () => ({ accessToken: "test-token" }),
  },
}));

import { api } from "../src/lib/api";

describe("api() helper", () => {
  it("GET without body sends no body", async () => {
    fetchMock.mockResolvedValueOnce({
      status: 200,
      ok: true,
      json: async () => ({ ok: true }),
    } as Response);

    await api("/v1/scans/123/start", { method: "GET" });

    expect(fetchMock).toHaveBeenCalledWith(
      "http://test.example/v1/scans/123/start",
      expect.objectContaining({ method: "GET", body: undefined }),
    );
  });

  it("POST without body sends '{}'", async () => {
    fetchMock.mockResolvedValueOnce({
      status: 200,
      ok: true,
      json: async () => ({ ok: true }),
    } as Response);

    await api("/v1/scans/123/start", { method: "POST" });

    expect(fetchMock).toHaveBeenCalledWith(
      "http://test.example/v1/scans/123/start",
      expect.objectContaining({
        method: "POST",
        headers: expect.objectContaining({ "content-type": "application/json" }),
        body: "{}",
      }),
    );
  });

  it("POST with body stringifies the body", async () => {
    fetchMock.mockResolvedValueOnce({
      status: 200,
      ok: true,
      json: async () => ({ ok: true }),
    } as Response);

    await api("/v1/scans/123/start", { method: "POST", body: { foo: "bar" } });

    expect(fetchMock).toHaveBeenCalledWith(
      "http://test.example/v1/scans/123/start",
      expect.objectContaining({ body: '{"foo":"bar"}' }),
    );
  });

  it("PUT without body sends '{}'", async () => {
    fetchMock.mockResolvedValueOnce({
      status: 200,
      ok: true,
      json: async () => ({ ok: true }),
    } as Response);

    await api("/v1/items/abc", { method: "PUT" });

    expect(fetchMock).toHaveBeenCalledWith(
      "http://test.example/v1/items/abc",
      expect.objectContaining({ method: "PUT", body: "{}" }),
    );
  });

  it("HEAD without body sends no body", async () => {
    fetchMock.mockResolvedValueOnce({
      status: 200,
      ok: true,
      json: async () => ({ ok: true }),
    } as Response);

    await api("/v1/health", { method: "HEAD" });

    expect(fetchMock).toHaveBeenCalledWith(
      "http://test.example/v1/health",
      expect.objectContaining({ method: "HEAD", body: undefined }),
    );
  });
});
