import { del, get, post, put } from "./api";

// Mock fetch globally
const mockFetch = jest.fn();
global.fetch = mockFetch;

describe("API functions", () => {
  beforeEach(() => {
    mockFetch.mockClear();
    // Reset environment variable
    process.env.NEXT_PUBLIC_WATCH_FINISHED_API = "http://localhost:3001";
  });

  afterEach(() => {
    delete process.env.NEXT_PUBLIC_WATCH_FINISHED_API;
  });

  describe("get", () => {
    it("should make a GET request with correct parameters", async () => {
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({ data: "test" })
      };
      mockFetch.mockResolvedValue(mockResponse);

      const result = await get("/test-endpoint", { param1: "value1" });

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test-endpoint?param1=value1",
        {
          method: "GET",
          credentials: "same-origin",
          headers: { Accept: "application/json" },
          signal: expect.any(AbortSignal)
        }
      );
      expect(result).toEqual({ data: "test" });
    });

    it("should handle timeout correctly", async () => {
      // Mock fetch to immediately throw AbortError
      const abortError = new Error("Request timeout");
      abortError.name = "AbortError";
      mockFetch.mockRejectedValue(abortError);

      await expect(get("/test-endpoint")).rejects.toThrow("Request timeout");
    });

    it("should throw error for non-ok response", async () => {
      const mockResponse = {
        ok: false,
        text: jest.fn().mockResolvedValue("Error message")
      };
      mockFetch.mockResolvedValue(mockResponse);

      await expect(get("/test-endpoint")).rejects.toThrow("Error message");
    });
  });

  describe("post", () => {
    it("should make a POST request with data", async () => {
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({ success: true })
      };
      mockFetch.mockResolvedValue(mockResponse);

      const result = await post("/test-endpoint", { key: "value" });

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test-endpoint",
        {
          method: "POST",
          credentials: "same-origin",
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json"
          },
          body: JSON.stringify({ key: "value" })
        }
      );
      expect(result).toEqual({ success: true });
    });

    it("should handle POST without data", async () => {
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({ success: true })
      };
      mockFetch.mockResolvedValue(mockResponse);

      await post("/test-endpoint");

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test-endpoint",
        expect.objectContaining({
          method: "POST",
          body: undefined
        })
      );
    });
  });

  describe("put", () => {
    it("should make a PUT request with timeout", async () => {
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({ updated: true })
      };
      mockFetch.mockResolvedValue(mockResponse);

      const result = await put("/test-endpoint", { key: "value" });

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test-endpoint",
        expect.objectContaining({
          method: "PUT",
          signal: expect.any(Object) // AbortSignal is an object
        })
      );
      expect(result).toEqual({ updated: true });
    });
  });

  describe("del", () => {
    it("should make a DELETE request with parameters", async () => {
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({ deleted: true })
      };
      mockFetch.mockResolvedValue(mockResponse);

      const result = await del("/test-endpoint", { id: "123" });

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test-endpoint?id=123",
        expect.objectContaining({
          method: "DELETE",
          signal: expect.any(Object) // AbortSignal is an object
        })
      );
      expect(result).toEqual({ deleted: true });
    });
  });

  describe("buildUrl", () => {
    it("should build URL with base API and path", () => {
      // This is testing the internal buildUrl function indirectly through the API calls
      const mockResponse = {
        ok: true,
        json: jest.fn().mockResolvedValue({})
      };
      mockFetch.mockResolvedValue(mockResponse);

      get("/test");

      expect(mockFetch).toHaveBeenCalledWith(
        "http://localhost:3001/test",
        expect.any(Object)
      );
    });
  });
});
