import React from "react";
import { BlogGridBase } from "./index";
import { BlogCategoryOption, BlogGridBaseProps } from "./types";

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

jest.mock("@shared/components/pagination", () => ({
  Pagination: ({ currentPage, totalPages, onPageChange, ariaLabel }: any) => (
    <nav aria-label={ariaLabel} data-testid="pagination">
      <span>
        Page {currentPage} of {totalPages}
      </span>
      <button data-testid="page-next" onClick={() => onPageChange(2)}>
        Next
      </button>
      <button data-testid="page-first" onClick={() => onPageChange(1)}>
        First
      </button>
    </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, imageComponent, index }: any) => (
    <a
      href={href}
      data-testid={`blog-card-${index}`}
      data-has-image={!!image}
      data-has-image-component={!!imageComponent}
    >
      {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" },
  },
  {
    slug: "article-3",
    title: "Article Three",
    shortDescription: "Desc 3",
    blogCreationDate: "2024-03-01",
    category: "tech",
  },
];

const defaultProps: BlogGridBaseProps = {
  paginatedArticles: mockArticles,
  totalArticles: 10,
  currentPage: 1,
  totalPages: 3,
  selectedCategory: categoryOptions[0],
  categoryOptions,
  onCategoryChange: jest.fn(),
  onPageChange: jest.fn(),
};

describe("BlogGridBase", () => {
  beforeEach(() => jest.clearAllMocks());

  describe("Rendering", () => {
    it("renders section with correct attributes", () => {
      const { container } = render(<BlogGridBase {...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 default title", () => {
      render(<BlogGridBase {...defaultProps} />);
      expect(screen.getByText("recent articles")).toBeInTheDocument();
    });

    it("renders custom title", () => {
      render(<BlogGridBase {...defaultProps} title="custom title" />);
      expect(screen.getByText("custom title")).toBeInTheDocument();
    });

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

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

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

    it("hides category controls when categoryOptions is empty", () => {
      render(<BlogGridBase {...defaultProps} categoryOptions={[]} />);
      expect(screen.queryByTestId("category-select")).not.toBeInTheDocument();
    });
  });

  describe("Slug handling", () => {
    it("keeps href unchanged when slug starts with /", () => {
      render(<BlogGridBase {...defaultProps} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "href",
        "/article-1"
      );
    });

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

  describe("Category filter", () => {
    it("calls onCategoryChange with selected category", () => {
      render(<BlogGridBase {...defaultProps} />);
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "tech" },
      });
      expect(defaultProps.onCategoryChange).toHaveBeenCalledWith({
        value: "tech",
        label: "Technology",
      });
    });

    it("does nothing when value is falsy", () => {
      render(<BlogGridBase {...defaultProps} />);
      fireEvent.change(screen.getByTestId("category-select"), {
        target: { value: "nonexistent" },
      });
      expect(defaultProps.onCategoryChange).not.toHaveBeenCalled();
    });

    it("works without onCategoryChange callback", () => {
      render(<BlogGridBase {...defaultProps} onCategoryChange={undefined} />);
      expect(() => {
        fireEvent.change(screen.getByTestId("category-select"), {
          target: { value: "tech" },
        });
      }).not.toThrow();
    });
  });

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

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

    it("calls onPageChange with page number", () => {
      render(<BlogGridBase {...defaultProps} />);
      fireEvent.click(screen.getByTestId("page-next"));
      expect(defaultProps.onPageChange).toHaveBeenCalledWith(2);
    });

    it("works without onPageChange callback", () => {
      render(<BlogGridBase {...defaultProps} onPageChange={undefined} />);
      expect(() => {
        fireEvent.click(screen.getByTestId("page-next"));
      }).not.toThrow();
    });
  });

  describe("Cover image handling", () => {
    it("passes image data when cover has url", () => {
      render(<BlogGridBase {...defaultProps} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-has-image",
        "true"
      );
    });

    it("passes undefined image when no cover", () => {
      render(<BlogGridBase {...defaultProps} />);
      expect(screen.getByTestId("blog-card-2")).toHaveAttribute(
        "data-has-image",
        "false"
      );
    });

    it("uses default width/height when not provided", () => {
      // article-2 has cover with url but no width/height
      render(<BlogGridBase {...defaultProps} />);
      expect(screen.getByTestId("blog-card-1")).toHaveAttribute(
        "data-has-image",
        "true"
      );
    });

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

    it("passes imageComponent to BlogCard", () => {
      const MockImage = (props: any) => <img {...props} />;
      render(<BlogGridBase {...defaultProps} imageComponent={MockImage} />);
      expect(screen.getByTestId("blog-card-0")).toHaveAttribute(
        "data-has-image-component",
        "true"
      );
    });
  });
});
