import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { FilterBar } from "./FilterBar";
import { TaskStatus, TaskPriority } from "@mosaic/shared";

describe("FilterBar", (): void => {
  const mockOnFilterChange = vi.fn();

  beforeEach((): void => {
    vi.clearAllMocks();
  });

  it("should render search input", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} />);
    expect(screen.getByPlaceholderText(/search/i)).toBeInTheDocument();
  });

  it("should render status filter", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} />);
    expect(screen.getByRole("button", { name: /status/i })).toBeInTheDocument();
  });

  it("should render priority filter", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} />);
    expect(screen.getByRole("button", { name: /priority/i })).toBeInTheDocument();
  });

  it("should render date range picker", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} />);
    expect(screen.getByPlaceholderText(/from date/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/to date/i)).toBeInTheDocument();
  });

  it("should render clear filters button when filters applied", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} initialFilters={{ search: "test" }} />);
    expect(screen.getByRole("button", { name: /clear filters/i })).toBeInTheDocument();
  });

  it("should not render clear filters button when no filters applied", (): void => {
    render(<FilterBar onFilterChange={mockOnFilterChange} />);
    expect(screen.queryByRole("button", { name: /clear filters/i })).not.toBeInTheDocument();
  });

  it("should debounce search input", async (): Promise<void> => {
    const user = userEvent.setup();
    render(<FilterBar onFilterChange={mockOnFilterChange} debounceMs={300} />);

    const searchInput = screen.getByPlaceholderText(/search/i);
    await user.type(searchInput, "test query");

    // Should not call immediately
    expect(mockOnFilterChange).not.toHaveBeenCalled();

    // Should call after debounce delay
    await waitFor(
      () => {
        expect(mockOnFilterChange).toHaveBeenCalledWith(
          expect.objectContaining({ search: "test query" })
        );
      },
      { timeout: 500 }
    );
  });

  it("should clear all filters when clear button clicked", async (): Promise<void> => {
    const user = userEvent.setup();
    render(
      <FilterBar
        onFilterChange={mockOnFilterChange}
        initialFilters={{
          search: "test",
          status: [TaskStatus.IN_PROGRESS],
          priority: [TaskPriority.HIGH],
        }}
      />
    );

    const clearButton = screen.getByRole("button", { name: /clear filters/i });
    await user.click(clearButton);

    expect(mockOnFilterChange).toHaveBeenCalledWith({});
  });

  it("should handle status selection", async (): Promise<void> => {
    const user = userEvent.setup();
    render(<FilterBar onFilterChange={mockOnFilterChange} />);

    const statusButton = screen.getByRole("button", { name: /status/i });
    await user.click(statusButton);

    // Note: Actual multi-select implementation would need to open a dropdown
    // This is a simplified test
  });

  it("should handle priority selection", async (): Promise<void> => {
    const user = userEvent.setup();
    render(<FilterBar onFilterChange={mockOnFilterChange} />);

    const priorityButton = screen.getByRole("button", { name: /priority/i });
    await user.click(priorityButton);

    // Note: Actual implementation would need to open a dropdown
  });

  it("should handle date range selection", async (): Promise<void> => {
    const user = userEvent.setup();
    render(<FilterBar onFilterChange={mockOnFilterChange} />);

    const fromDate = screen.getByPlaceholderText(/from date/i);
    const toDate = screen.getByPlaceholderText(/to date/i);

    await user.type(fromDate, "2024-01-01");
    await user.type(toDate, "2024-12-31");

    await waitFor(() => {
      expect(mockOnFilterChange).toHaveBeenCalled();
    });
  });

  it("should display active filter count", (): void => {
    render(
      <FilterBar
        onFilterChange={mockOnFilterChange}
        initialFilters={{
          status: [TaskStatus.IN_PROGRESS, TaskStatus.NOT_STARTED],
          priority: [TaskPriority.HIGH],
        }}
      />
    );

    // Should show 3 active filters (2 statuses + 1 priority)
    expect(screen.getByText(/3/)).toBeInTheDocument();
  });
});
