import React from "react";
import { Pagination } from "./index";

import { fireEvent, render, screen } from "@testing-library/react";

// Mock dependencies
jest.mock("@shared/components/link", () => ({
  Link: ({ children, href, onClick, className, ...rest }: any) => (
    <a href={href} onClick={onClick} className={className} {...rest}>
      {children}
    </a>
  ),
}));

jest.mock("@shared/components/material-icon", () => ({
  MaterialIcon: ({ name, ...rest }: any) => (
    <span data-testid={`icon-${name}`} {...rest}>
      {name}
    </span>
  ),
}));

describe("Pagination", () => {
  const mockOnPageChange = jest.fn();
  const mockGetPageHref = (page: number) => `/blog?page=${page}`;

  beforeEach(() => {
    mockOnPageChange.mockClear();
  });

  describe("Rendering", () => {
    it("renders the pagination nav with default aria-label", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(screen.getByRole("navigation")).toHaveAttribute(
        "aria-label",
        "Pagination"
      );
    });

    it("renders with custom aria-label", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
          ariaLabel="Blog pages"
        />
      );
      expect(screen.getByRole("navigation")).toHaveAttribute(
        "aria-label",
        "Blog pages"
      );
    });

    it("renders previous and next navigation links", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to previous page" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to next page" })
      ).toBeInTheDocument();
    });

    it("renders chevron icons in nav links", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(screen.getByTestId("icon-chevron_left")).toBeInTheDocument();
      expect(screen.getByTestId("icon-chevron_right")).toBeInTheDocument();
    });
  });

  describe("Link states", () => {
    it("disables previous link on first page", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const prevLink = screen.getByRole("link", { name: "Go to previous page" });
      expect(prevLink).toHaveAttribute("aria-disabled", "true");
      expect(prevLink).toHaveAttribute("tabindex", "-1");
    });

    it("enables previous link when not on first page", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const prevLink = screen.getByRole("link", { name: "Go to previous page" });
      expect(prevLink).not.toHaveAttribute("aria-disabled", "true");
    });

    it("disables next link on last page", () => {
      render(
        <Pagination
          currentPage={5}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const nextLink = screen.getByRole("link", { name: "Go to next page" });
      expect(nextLink).toHaveAttribute("aria-disabled", "true");
      expect(nextLink).toHaveAttribute("tabindex", "-1");
    });

    it("enables next link when not on last page", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const nextLink = screen.getByRole("link", { name: "Go to next page" });
      expect(nextLink).not.toHaveAttribute("aria-disabled", "true");
    });

    it("marks current page with aria-current='page'", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 3" })
      ).toHaveAttribute("aria-current", "page");
    });

    it("does not set aria-current on non-current pages", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).not.toHaveAttribute("aria-current");
    });

    it("applies active class to current page link", () => {
      render(
        <Pagination
          currentPage={2}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const activeLink = screen.getByRole("link", { name: "Go to page 2" });
      expect(activeLink.className).toContain("bg-bg-surface-active");
      expect(activeLink.className).toContain("font-bold");
    });

    it("does not apply active class to non-current page links", () => {
      render(
        <Pagination
          currentPage={2}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const inactiveLink = screen.getByRole("link", {
        name: "Go to page 1",
      });
      expect(inactiveLink.className).not.toContain("bg-bg-surface-active");
    });

    it("renders correct href for page links", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 3" })
      ).toHaveAttribute("href", "/blog?page=3");
    });
  });

  describe("Page navigation clicks", () => {
    it("calls onPageChange with previous page when previous link clicked", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      fireEvent.click(
        screen.getByRole("link", { name: "Go to previous page" })
      );
      expect(mockOnPageChange).toHaveBeenCalledWith(2);
    });

    it("calls onPageChange with next page when next link clicked", () => {
      render(
        <Pagination
          currentPage={3}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      fireEvent.click(screen.getByRole("link", { name: "Go to next page" }));
      expect(mockOnPageChange).toHaveBeenCalledWith(4);
    });

    it("calls onPageChange with clicked page number", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      fireEvent.click(screen.getByRole("link", { name: "Go to page 4" }));
      expect(mockOnPageChange).toHaveBeenCalledWith(4);
    });

    it("does not call onPageChange when disabled previous link is clicked", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      fireEvent.click(
        screen.getByRole("link", { name: "Go to previous page" })
      );
      expect(mockOnPageChange).not.toHaveBeenCalled();
    });

    it("does not call onPageChange when disabled next link is clicked", () => {
      render(
        <Pagination
          currentPage={5}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      fireEvent.click(screen.getByRole("link", { name: "Go to next page" }));
      expect(mockOnPageChange).not.toHaveBeenCalled();
    });
  });

  describe("buildPageItems algorithm — total pages <= 7", () => {
    it("renders all pages for totalPages=1", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={1}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      expect(screen.queryByText("…")).not.toBeInTheDocument();
    });

    it("renders all pages for totalPages=5", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      for (let i = 1; i <= 5; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
      expect(screen.queryByText("…")).not.toBeInTheDocument();
    });

    it("renders all pages for totalPages=7", () => {
      render(
        <Pagination
          currentPage={4}
          totalPages={7}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      for (let i = 1; i <= 7; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
      expect(screen.queryByText("…")).not.toBeInTheDocument();
    });
  });

  describe("buildPageItems algorithm — current near start (current <= 4)", () => {
    it("shows pages 1-5 and ellipsis then last page when on page 1", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      for (let i = 1; i <= 5; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
      expect(screen.getByText("…")).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 10" })
      ).toBeInTheDocument();
      expect(
        screen.queryByRole("link", { name: "Go to page 6" })
      ).not.toBeInTheDocument();
    });

    it("shows pages 1-5, ellipsis, last for page 4 of 10", () => {
      render(
        <Pagination
          currentPage={4}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      for (let i = 1; i <= 5; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
      expect(screen.getByText("…")).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 10" })
      ).toBeInTheDocument();
    });
  });

  describe("buildPageItems algorithm — current near end (current >= total - 3)", () => {
    it("shows first page, ellipsis, last 5 pages when on last page", () => {
      render(
        <Pagination
          currentPage={10}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      expect(screen.getByText("…")).toBeInTheDocument();
      for (let i = 6; i <= 10; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
    });

    it("shows first, ellipsis, last 5 for page 7 of 10", () => {
      render(
        <Pagination
          currentPage={7}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      expect(screen.getByText("…")).toBeInTheDocument();
      for (let i = 6; i <= 10; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
    });
  });

  describe("buildPageItems algorithm — current in middle", () => {
    it("shows first, ellipsis, current-1/current/current+1, ellipsis, last", () => {
      render(
        <Pagination
          currentPage={5}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 4" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 5" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 6" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 10" })
      ).toBeInTheDocument();
      const ellipses = screen.getAllByText("…");
      expect(ellipses).toHaveLength(2);
    });

    it("renders ellipsis as non-interactive with aria-hidden", () => {
      render(
        <Pagination
          currentPage={5}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      const ellipses = screen.getAllByText("…");
      ellipses.forEach(el => {
        expect(el).toHaveAttribute("aria-hidden", "true");
        expect(el.tagName).toBe("SPAN");
      });
    });

    it("shows correct pages for page 6 of 10", () => {
      render(
        <Pagination
          currentPage={6}
          totalPages={10}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 5" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 6" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 7" })
      ).toBeInTheDocument();
      expect(
        screen.getByRole("link", { name: "Go to page 10" })
      ).toBeInTheDocument();
      expect(screen.getAllByText("…")).toHaveLength(2);
    });
  });

  describe("Edge cases", () => {
    it("handles single page (both nav links disabled)", () => {
      render(
        <Pagination
          currentPage={1}
          totalPages={1}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to previous page" })
      ).toHaveAttribute("aria-disabled", "true");
      expect(
        screen.getByRole("link", { name: "Go to next page" })
      ).toHaveAttribute("aria-disabled", "true");
    });

    it("handles totalPages=8 with current=4 (near-start boundary)", () => {
      render(
        <Pagination
          currentPage={4}
          totalPages={8}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      for (let i = 1; i <= 5; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
      expect(
        screen.getByRole("link", { name: "Go to page 8" })
      ).toBeInTheDocument();
    });

    it("handles totalPages=8 with current=5 (near-end boundary)", () => {
      render(
        <Pagination
          currentPage={5}
          totalPages={8}
          onPageChange={mockOnPageChange}
          getPageHref={mockGetPageHref}
        />
      );
      expect(
        screen.getByRole("link", { name: "Go to page 1" })
      ).toBeInTheDocument();
      for (let i = 4; i <= 8; i++) {
        expect(
          screen.getByRole("link", { name: `Go to page ${i}` })
        ).toBeInTheDocument();
      }
    });
  });
});
