import { describe, it, expect } from "@jest/globals";
import {
  DEFAULT_PAGE_SIZE,
  MAX_PAGE_SIZE,
  DEFAULT_PAGE,
  getPaginationParams,
  getSkip,
  buildPaginationMeta,
  createPaginatedResponse,
  getPrismaOffsetPagination,
  getQueryParams,
} from "@/lib/pagination";
import { NextRequest } from "next/server";

describe("Pagination Utilities", () => {
  describe("getPaginationParams", () => {
    it("should return default values when no params provided", () => {
      const request = new NextRequest("http://localhost:9000/api/test");
      const params = getPaginationParams(request);

      expect(params.page).toBe(DEFAULT_PAGE);
      expect(params.limit).toBe(DEFAULT_PAGE_SIZE);
      expect(params.cursor).toBeUndefined();
    });

    it("should parse page and limit from URL", () => {
      const request = new NextRequest(
        "http://localhost:9000/api/test?page=2&limit=50",
      );
      const params = getPaginationParams(request);

      expect(params.page).toBe(2);
      expect(params.limit).toBe(50);
    });

    it("should enforce maximum page size", () => {
      const request = new NextRequest(
        "http://localhost:9000/api/test?limit=200",
      );
      const params = getPaginationParams(request);

      expect(params.limit).toBe(MAX_PAGE_SIZE);
    });

    it("should enforce minimum page size of 1", () => {
      const request = new NextRequest("http://localhost:9000/api/test?limit=0");
      const params = getPaginationParams(request);

      expect(params.limit).toBe(1);
    });

    it("should enforce minimum page of 1", () => {
      const request = new NextRequest("http://localhost:9000/api/test?page=0");
      const params = getPaginationParams(request);

      expect(params.page).toBe(1);
    });

    it("should parse cursor parameter", () => {
      const request = new NextRequest(
        "http://localhost:9000/api/test?cursor=abc123",
      );
      const params = getPaginationParams(request);

      expect(params.cursor).toBe("abc123");
    });
  });

  describe("getSkip", () => {
    it("should calculate correct skip for page 1", () => {
      expect(getSkip(1, 20)).toBe(0);
    });

    it("should calculate correct skip for page 2", () => {
      expect(getSkip(2, 20)).toBe(20);
    });

    it("should calculate correct skip for page 3 with different limit", () => {
      expect(getSkip(3, 50)).toBe(100);
    });
  });

  describe("buildPaginationMeta", () => {
    it("should build correct metadata for first page", () => {
      const meta = buildPaginationMeta(100, 1, 20);

      expect(meta.total).toBe(100);
      expect(meta.page).toBe(1);
      expect(meta.limit).toBe(20);
      expect(meta.totalPages).toBe(5);
      expect(meta.hasNext).toBe(true);
      expect(meta.hasPrev).toBe(false);
    });

    it("should build correct metadata for middle page", () => {
      const meta = buildPaginationMeta(100, 3, 20);

      expect(meta.totalPages).toBe(5);
      expect(meta.hasNext).toBe(true);
      expect(meta.hasPrev).toBe(true);
    });

    it("should build correct metadata for last page", () => {
      const meta = buildPaginationMeta(100, 5, 20);

      expect(meta.hasNext).toBe(false);
      expect(meta.hasPrev).toBe(true);
    });

    it("should handle non-even division", () => {
      const meta = buildPaginationMeta(95, 1, 20);

      expect(meta.totalPages).toBe(5); // 95 / 20 = 4.75 -> 5 pages
    });
  });

  describe("createPaginatedResponse", () => {
    it("should create properly formatted paginated response", () => {
      const data = [{ id: 1 }, { id: 2 }, { id: 3 }];
      const response = createPaginatedResponse(data, 100, 1, 20);

      expect(response.data).toBe(data);
      expect(response.pagination.total).toBe(100);
      expect(response.pagination.page).toBe(1);
      expect(response.pagination.limit).toBe(20);
      expect(response.pagination.totalPages).toBe(5);
      expect(response.pagination.hasNext).toBe(true);
      expect(response.pagination.hasPrev).toBe(false);
    });
  });

  describe("getPrismaOffsetPagination", () => {
    it("should generate correct Prisma params for page 1", () => {
      const params = getPrismaOffsetPagination(1, 20);

      expect(params.skip).toBe(0);
      expect(params.take).toBe(20);
    });

    it("should generate correct Prisma params for page 3", () => {
      const params = getPrismaOffsetPagination(3, 50);

      expect(params.skip).toBe(100);
      expect(params.take).toBe(50);
    });
  });

  describe("getQueryParams", () => {
    it("should parse all query parameters", () => {
      const searchParams = new URLSearchParams(
        "page=2&limit=30&search=test&sortBy=name&sortOrder=asc",
      );
      const params = getQueryParams(searchParams);

      expect(params.page).toBe(2);
      expect(params.limit).toBe(30);
      expect(params.search).toBe("test");
      expect(params.sortBy).toBe("name");
      expect(params.sortOrder).toBe("asc");
    });

    it("should use defaults when params missing", () => {
      const searchParams = new URLSearchParams("");
      const params = getQueryParams(searchParams);

      expect(params.page).toBe(1);
      expect(params.limit).toBe(DEFAULT_PAGE_SIZE);
      expect(params.search).toBeUndefined();
      expect(params.sortBy).toBeUndefined();
      expect(params.sortOrder).toBe("desc");
    });

    it("should enforce limits", () => {
      const searchParams = new URLSearchParams("page=-1&limit=500");
      const params = getQueryParams(searchParams);

      expect(params.page).toBe(1);
      expect(params.limit).toBe(MAX_PAGE_SIZE);
    });
  });
});
