/**
 * IssueFilters Component Tests
 */

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { IssueFilters } from '@/features/issues/components/IssueFilters';
import type { IssueFilters as IssueFiltersType } from '@/features/issues/types';

describe('IssueFilters', () => {
  const defaultFilters: IssueFiltersType = {
    status: 'all',
    priority: 'all',
    sprint: 'all',
    assignee: 'all',
  };

  const mockOnFiltersChange = jest.fn();

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

  it('renders search input', () => {
    render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

    expect(screen.getByPlaceholderText('Search issues...')).toBeInTheDocument();
  });

  it('calls onFiltersChange when search changes', async () => {
    const user = userEvent.setup();
    render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

    const searchInput = screen.getByPlaceholderText('Search issues...');
    await user.type(searchInput, 'test');

    // onFiltersChange should be called at least once
    expect(mockOnFiltersChange).toHaveBeenCalled();
    // The final state should contain the search term 'test' (may be in the last call)
    const allCalls = mockOnFiltersChange.mock.calls;
    const lastCall = allCalls[allCalls.length - 1][0];
    // The search value could include the typed characters
    expect(lastCall.search).toMatch(/t/);
  });

  it('renders status filter', () => {
    render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

    expect(screen.getByRole('combobox', { name: /filter by status/i })).toBeInTheDocument();
  });

  it('toggles extended filters when filter button is clicked', async () => {
    const user = userEvent.setup();
    render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

    // Extended filters should not be visible initially
    expect(screen.queryByLabelText('Priority')).not.toBeInTheDocument();

    // Click the filter toggle button
    const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
    await user.click(filterButton);

    // Extended filters should now be visible
    expect(screen.getByLabelText('Priority')).toBeInTheDocument();
    expect(screen.getByLabelText('Sprint')).toBeInTheDocument();
    expect(screen.getByLabelText('Assignee')).toBeInTheDocument();
  });

  it('shows clear filters button when filters are active', async () => {
    const user = userEvent.setup();
    const activeFilters: IssueFiltersType = {
      ...defaultFilters,
      status: 'open',
    };

    render(<IssueFilters filters={activeFilters} onFiltersChange={mockOnFiltersChange} />);

    // Open extended filters
    const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
    await user.click(filterButton);

    // Clear filters button should be visible
    expect(screen.getByRole('button', { name: /clear filters/i })).toBeInTheDocument();
  });

  it('clears filters when clear button is clicked', async () => {
    const user = userEvent.setup();
    const activeFilters: IssueFiltersType = {
      ...defaultFilters,
      status: 'open',
      search: 'test',
    };

    render(<IssueFilters filters={activeFilters} onFiltersChange={mockOnFiltersChange} />);

    // Open extended filters
    const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
    await user.click(filterButton);

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

    // Should call onFiltersChange with cleared filters
    expect(mockOnFiltersChange).toHaveBeenCalledWith({
      search: undefined,
      status: 'all',
      priority: 'all',
      sprint: 'all',
      assignee: 'all',
      labels: undefined,
    });
  });

  it('applies custom className', () => {
    const { container } = render(
      <IssueFilters
        filters={defaultFilters}
        onFiltersChange={mockOnFiltersChange}
        className="custom-class"
      />
    );

    expect(container.firstChild).toHaveClass('custom-class');
  });

  describe('Filter change handlers', () => {
    it('renders status filter with correct trigger', () => {
      render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

      const statusTrigger = screen.getByRole('combobox', { name: /filter by status/i });
      expect(statusTrigger).toBeInTheDocument();
    });

    it('renders priority filter when extended filters open', async () => {
      const user = userEvent.setup();
      render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByLabelText('Priority')).toBeInTheDocument();
    });

    it('renders sprint filter when extended filters open', async () => {
      const user = userEvent.setup();
      render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByLabelText('Sprint')).toBeInTheDocument();
    });

    it('renders assignee filter when extended filters open', async () => {
      const user = userEvent.setup();
      render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByLabelText('Assignee')).toBeInTheDocument();
    });
  });

  describe('Active filters detection', () => {
    it('shows clear button when search is active', async () => {
      const user = userEvent.setup();
      const filtersWithSearch: IssueFiltersType = {
        ...defaultFilters,
        search: 'test query',
      };

      render(<IssueFilters filters={filtersWithSearch} onFiltersChange={mockOnFiltersChange} />);

      // Open extended filters
      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByRole('button', { name: /clear filters/i })).toBeInTheDocument();
    });

    it('shows clear button when priority is not all', async () => {
      const user = userEvent.setup();
      const filtersWithPriority: IssueFiltersType = {
        ...defaultFilters,
        priority: 'critical',
      };

      render(<IssueFilters filters={filtersWithPriority} onFiltersChange={mockOnFiltersChange} />);

      // Open extended filters
      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByRole('button', { name: /clear filters/i })).toBeInTheDocument();
    });

    it('shows clear button when sprint is not all', async () => {
      const user = userEvent.setup();
      const filtersWithSprint: IssueFiltersType = {
        ...defaultFilters,
        sprint: 'Sprint 1',
      };

      render(<IssueFilters filters={filtersWithSprint} onFiltersChange={mockOnFiltersChange} />);

      // Open extended filters
      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByRole('button', { name: /clear filters/i })).toBeInTheDocument();
    });

    it('shows clear button when assignee is not all', async () => {
      const user = userEvent.setup();
      const filtersWithAssignee: IssueFiltersType = {
        ...defaultFilters,
        assignee: 'user-123',
      };

      render(<IssueFilters filters={filtersWithAssignee} onFiltersChange={mockOnFiltersChange} />);

      // Open extended filters
      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.getByRole('button', { name: /clear filters/i })).toBeInTheDocument();
    });

    it('does not show clear button when all filters are default', async () => {
      const user = userEvent.setup();
      render(<IssueFilters filters={defaultFilters} onFiltersChange={mockOnFiltersChange} />);

      // Open extended filters
      const filterButton = screen.getByRole('button', { name: /toggle extended filters/i });
      await user.click(filterButton);

      expect(screen.queryByRole('button', { name: /clear filters/i })).not.toBeInTheDocument();
    });
  });

  describe('Search empty handling', () => {
    it('clears search when input is emptied', async () => {
      const user = userEvent.setup();
      const filtersWithSearch: IssueFiltersType = {
        ...defaultFilters,
        search: 'test',
      };

      render(<IssueFilters filters={filtersWithSearch} onFiltersChange={mockOnFiltersChange} />);

      const searchInput = screen.getByPlaceholderText('Search issues...');
      await user.clear(searchInput);

      // Should call with undefined search
      const lastCall = mockOnFiltersChange.mock.calls[mockOnFiltersChange.mock.calls.length - 1][0];
      expect(lastCall.search).toBeUndefined();
    });
  });
});
