import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { QuestionFilters } from "./question-filters";
import type { Category, Pattern } from "@/types";

const mockPush = vi.fn();
const mockSearchParams = new URLSearchParams();

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

const mockCategories: Category[] = [
  { id: "1", name: "Arrays", slug: "arrays", description: null, question_count: 5 },
  { id: "2", name: "Strings", slug: "strings", description: null, question_count: 3 },
];

const mockPatterns: Pattern[] = [
  {
    id: "1",
    name: "Two Pointers",
    slug: "two-pointers",
    description: null,
    when_to_use: null,
    question_count: 4,
  },
  {
    id: "2",
    name: "Sliding Window",
    slug: "sliding-window",
    description: null,
    when_to_use: null,
    question_count: 2,
  },
];

describe("QuestionFilters", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockSearchParams.delete("category");
    mockSearchParams.delete("pattern");
    mockSearchParams.delete("page");
  });

  it("renders category filter with label", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    expect(screen.getByLabelText("Category")).toBeInTheDocument();
  });

  it("renders pattern filter with label", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    expect(screen.getByLabelText("Pattern")).toBeInTheDocument();
  });

  it("renders all category options with counts", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    expect(screen.getByText("All Categories")).toBeInTheDocument();
    expect(screen.getByText("Arrays (5)")).toBeInTheDocument();
    expect(screen.getByText("Strings (3)")).toBeInTheDocument();
  });

  it("renders all pattern options with counts", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    expect(screen.getByText("All Patterns")).toBeInTheDocument();
    expect(screen.getByText("Two Pointers (4)")).toBeInTheDocument();
    expect(screen.getByText("Sliding Window (2)")).toBeInTheDocument();
  });

  it("navigates when category is selected", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    const categorySelect = screen.getByLabelText("Category");
    fireEvent.change(categorySelect, { target: { value: "arrays" } });
    expect(mockPush).toHaveBeenCalledWith("/questions?category=arrays");
  });

  it("navigates when pattern is selected", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
      />
    );
    const patternSelect = screen.getByLabelText("Pattern");
    fireEvent.change(patternSelect, { target: { value: "two-pointers" } });
    expect(mockPush).toHaveBeenCalledWith("/questions?pattern=two-pointers");
  });

  it("removes category param when All Categories is selected", () => {
    mockSearchParams.set("category", "arrays");
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentCategory="arrays"
      />
    );
    const categorySelect = screen.getByLabelText("Category");
    fireEvent.change(categorySelect, { target: { value: "" } });
    expect(mockPush).toHaveBeenCalledWith("/questions?");
  });

  it("removes pattern param when All Patterns is selected", () => {
    mockSearchParams.set("pattern", "two-pointers");
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentPattern="two-pointers"
      />
    );
    const patternSelect = screen.getByLabelText("Pattern");
    fireEvent.change(patternSelect, { target: { value: "" } });
    expect(mockPush).toHaveBeenCalledWith("/questions?");
  });

  it("shows current category as selected", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentCategory="arrays"
      />
    );
    const categorySelect = screen.getByLabelText("Category") as HTMLSelectElement;
    expect(categorySelect.value).toBe("arrays");
  });

  it("shows current pattern as selected", () => {
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentPattern="two-pointers"
      />
    );
    const patternSelect = screen.getByLabelText("Pattern") as HTMLSelectElement;
    expect(patternSelect.value).toBe("two-pointers");
  });

  it("resets page when filter changes", () => {
    mockSearchParams.set("page", "3");
    mockSearchParams.set("category", "strings");
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentCategory="strings"
      />
    );
    const categorySelect = screen.getByLabelText("Category");
    fireEvent.change(categorySelect, { target: { value: "arrays" } });
    expect(mockPush).toHaveBeenCalledWith("/questions?category=arrays");
  });

  it("preserves other params when changing category", () => {
    mockSearchParams.set("pattern", "two-pointers");
    render(
      <QuestionFilters
        categories={mockCategories}
        patterns={mockPatterns}
        currentPattern="two-pointers"
      />
    );
    const categorySelect = screen.getByLabelText("Category");
    fireEvent.change(categorySelect, { target: { value: "arrays" } });
    expect(mockPush).toHaveBeenCalledWith(
      "/questions?pattern=two-pointers&category=arrays"
    );
  });
});
