import React from "react";
import { BlogGrid } from "./index";
import { BlogCategoryOption, BlogGridProps } from "./types";

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

const mockPush = jest.fn();
let mockSearchParams = new URLSearchParams("");

jest.mock("next/navigation", () => ({
  useRouter: () => ({ push: mockPush }),
  usePathname: () => "/blog",
  useSearchParams: () => mockSearchParams,
}));

jest.mock("@shared/components/pagination", () => ({
  Pagination: ({
    currentPage,
    totalPages,
    onPageChange,
    getPageHref,
    ariaLabel,
  }: any) => (
    <nav aria-label={ariaLabel} data-testid="pagination">
      <span>
        Page {currentPage} of {totalPages}
      </span>
      <a
        data-testid="page-next"
        href={getPageHref?.(2)}
        onClick={() => onPageChange(2)}
      >
        Next
      </a>
      <a
        data-testid="page-first"
        href={getPageHref?.(1)}
        onClick={() => onPageChange(1)}
      >
        First
      </a>
    </nav>
  ),
}));

jest.mock("@shared/components/select", () => ({
  Select: ({ options, value, onChange, className }: any) => (
    <select
      data-testid="category-select"
      className={className}
      value={value?.value}
      onChange={e => {
        const opt = options.find((o: any) => o.value === e.target.value);
        onChange(opt);
      }}
    >
      {options.map((o: any) => (
        <option key={o.value} value={o.value}>
          {o.label}
        </option>
      ))}
    </select>
  ),
}));

jest.mock("@shared/components/text", () => ({
  Text: ({ as: Tag = "span", children, className }: any) => (
    <Tag className={className}>{children}</Tag>
  ),
}));

jest.mock("@shared/contentful/blocks/cards/blog-card", () => ({
  BlogCard: ({ href, title, category, image, index }: any) => (
    <a
      href={href}
      data-testid={`blog-card-${index}`}
      data-image-src={image?.src || ""}
      data-image-alt={image?.alt || ""}
      data-image-width={image?.width || ""}
      data-image-height={image?.height || ""}
    >
      {title} - {category}
    </a>
  ),
}));

const categoryOptions: BlogCategoryOption[] = [
  { value: "all", label: "All Categories" },
  { value: "tech", label: "Technology" },
  { value: "news", label: "News" },
];

const mockArticles = [
  {
    slug: "/article-1",
    title: "Article One",
    shortDescription: "Desc 1",
    blogCreationDate: "2024-01-01",
    category: "tech",
    cover: {
      url: "https://img.test/1.jpg",
      width: 600,
      height: 338,
      title: "Cover 1",
    },
  },
  {
    slug: "article-2",
    title: "Article Two",
    shortDescription: "Desc 2",
    blogCreationDate: "2024-02-01",
    category: "news",
    cover: {
      url: "https://img.test/2.jpg",
      width: 800,
      height: 450,
      title: "",
    },
  },
  {
    slug: "article-3",
    title: "Article Three",
    shortDescription: "Desc 3",
    blogCreationDate: "2024-03-01",
    category: "tech",
  },
];

const defaultProps: BlogGridProps = {
  paginatedArticles: mockArticles,
  totalArticles: 10,
  currentPage: 1,
  totalPages: 3,
  selectedCategory: categoryOptions[0],
  categoryOptions,
};

describe("BlogGrid", () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockSearchParams = new URLSearchParams("");
    window.scrollTo = jest.fn();
  });

  describe("Rendering", () => {
    it("renders section with correct aria-label and data attributes", () => {
      const { container } = render(<BlogGrid {...defaultProps} />);
      const section = container.querySelector("section");
      expect(section).toHaveAttribute("aria-label", "Blog articles");
      expect(section).toHaveAttribute("data-section-type", "blogs-grid");
      expect(section).toHaveAttribute("data-section-index", "0");
    });

    it("renders article count text", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByText("3 of 10 articles")).toBeInTheDocument();
    });

    it("renders all blog cards", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("blog-card-0")).toBeInTheDocument();
      expect(screen.getByTestId("blog-card-1")).toBeInTheDocument();
      expect(screen.getByTestId("blog-card-2")).toBeInTheDocument();
    });

    it("renders blog card with correct href when slug starts with /", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "href",
        "/article-1"
      );
    });

    it("prepends / to slug when it does not start with /", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("blog-card-1")).toHaveAttribute(
        "href",
        "/article-2"
      );
    });

    it("renders empty state when no articles", () => {
      render(<BlogGrid {...defaultProps} paginatedArticles={[]} />);
      expect(screen.getByText("No articles found.")).toBeInTheDocument();
    });

    it("does not render pagination when totalPages is 1", () => {
      render(<BlogGrid {...defaultProps} totalPages={1} />);
      expect(screen.queryByTestId("pagination")).not.toBeInTheDocument();
    });

    it("renders pagination when totalPages > 1", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("pagination")).toBeInTheDocument();
    });
  });

  describe("Category filter", () => {
    it("navigates with category param on selection", () => {
      render(<BlogGrid {...defaultProps} />);
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "tech" },
      });
      expect(mockPush).toHaveBeenCalledWith("/blog?category=tech", {
        scroll: false,
      });
    });

    it("removes category param when 'all' is selected", () => {
      render(<BlogGrid {...defaultProps} />);
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "all" },
      });
      expect(mockPush).toHaveBeenCalledWith("/blog?", { scroll: false });
    });

    it("deletes page param when category changes", () => {
      mockSearchParams = new URLSearchParams("page=3&category=news");
      render(<BlogGrid {...defaultProps} />);
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "tech" },
      });
      expect(mockPush).toHaveBeenCalledWith("/blog?category=tech", {
        scroll: false,
      });
    });

    it("does nothing when onChange receives falsy value", () => {
      render(<BlogGrid {...defaultProps} />);
      // Simulate onChange with a value not found in options (returns undefined)
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "nonexistent" },
      });
      expect(mockPush).not.toHaveBeenCalled();
    });
  });

  describe("Pagination", () => {
    it("builds page href with page param", () => {
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("page-next")).toHaveAttribute(
        "href",
        "/blog?page=2"
      );
    });

    it("removes page param when building href for page 1", () => {
      mockSearchParams = new URLSearchParams("page=2");
      render(<BlogGrid {...defaultProps} currentPage={2} />);
      expect(screen.getByTestId("page-first")).toHaveAttribute("href", "/blog");
    });

    it("keeps other params when building page href", () => {
      mockSearchParams = new URLSearchParams("category=tech");
      render(<BlogGrid {...defaultProps} />);
      expect(screen.getByTestId("page-first")).toHaveAttribute(
        "href",
        "/blog?category=tech"
      );
    });

    it("scrolls to top when currentPage changes", () => {
      const { rerender } = render(<BlogGrid {...defaultProps} />);
      expect(window.scrollTo).not.toHaveBeenCalled();
      rerender(<BlogGrid {...defaultProps} currentPage={2} />);
      expect(window.scrollTo).toHaveBeenCalledWith({
        top: 0,
        behavior: "smooth",
      });
    });
  });

  describe("Cover image handling", () => {
    it("renders card with full cover image data", () => {
      render(<BlogGrid {...defaultProps} />);
      const card = screen.getByTestId("blog-card-0");
      expect(card).toHaveAttribute("data-image-src", "https://img.test/1.jpg");
      expect(card).toHaveAttribute("data-image-alt", "Cover 1");
      expect(card).toHaveAttribute("data-image-width", "600");
      expect(card).toHaveAttribute("data-image-height", "338");
    });

    it("renders card without cover image when cover is undefined", () => {
      render(<BlogGrid {...defaultProps} />);
      const card = screen.getByTestId("blog-card-2");
      expect(card).toHaveAttribute("data-image-src", "");
    });

    it("uses article title as alt fallback when cover title is empty", () => {
      const articles = [
        {
          slug: "test-article",
          title: "Test Title",
          cover: {
            url: "https://img.test/x.jpg",
            width: 600,
            height: 338,
            title: "",
          },
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-image-alt",
        "Test Title"
      );
    });

    it("uses default alt text when both cover title and article title are missing", () => {
      const articles = [
        {
          slug: "no-title",
          cover: { url: "https://img.test/y.jpg" },
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-image-alt",
        "Blog article image"
      );
    });

    it("uses default width and height when not provided in cover", () => {
      const articles = [
        {
          slug: "no-dimensions",
          title: "No Dimensions",
          cover: { url: "https://img.test/z.jpg", title: "Cover" },
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      const card = screen.getByTestId("blog-card-0");
      expect(card).toHaveAttribute("data-image-width", "600");
      expect(card).toHaveAttribute("data-image-height", "338");
    });

    it("uses provided width and height from cover", () => {
      const articles = [
        {
          slug: "with-dimensions",
          title: "With Dimensions",
          cover: {
            url: "https://img.test/w.jpg",
            title: "Cover",
            width: 800,
            height: 450,
          },
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      const card = screen.getByTestId("blog-card-0");
      expect(card).toHaveAttribute("data-image-width", "800");
      expect(card).toHaveAttribute("data-image-height", "450");
    });

    it("handles article with cover set to null", () => {
      const articles = [
        {
          slug: "null-cover",
          title: "Null Cover",
          cover: null as any,
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-image-src",
        ""
      );
    });

    it("handles article with cover url empty string", () => {
      const articles = [
        {
          slug: "empty-url",
          title: "Empty URL",
          cover: { url: "", title: "Cover" },
        },
      ];
      render(<BlogGrid {...defaultProps} paginatedArticles={articles} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-image-src",
        ""
      );
    });
  });
});
