import { describe, test, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AdvancedSearchPanel from '../AdvancedSearchPanel';

const mockSettings = {
  useEnhancedSearch: true,
  searchMode: 'simple' as const,
  includeSnippets: true,
  snippetLength: 200,
  fuzzyThreshold: 0.8,
  resultLimit: 100,
  includeOcrText: true,
  includeFileContent: true,
  includeFilenames: true,
  boostRecentDocs: false,
  enableAutoCorrect: true,
};

const mockPresets = [
  {
    name: 'Fast Search',
    settings: {
      ...mockSettings,
      includeSnippets: false,
      resultLimit: 50,
    },
  },
  {
    name: 'Detailed Search',
    settings: {
      ...mockSettings,
      snippetLength: 400,
      resultLimit: 200,
    },
  },
];

describe('AdvancedSearchPanel', () => {
  const mockOnSettingsChange = vi.fn();
  const mockOnExpandedChange = vi.fn();
  const mockOnSavePreset = vi.fn();
  const mockOnLoadPreset = vi.fn();

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

  test('renders collapsed state by default', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={false}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    expect(screen.getByText('Advanced Search Options')).toBeInTheDocument();
    expect(screen.getByText('Customize search behavior and result display')).toBeInTheDocument();
    expect(screen.getByText('SIMPLE')).toBeInTheDocument();
    expect(screen.queryByText('Search Behavior')).not.toBeInTheDocument();
  });

  test('expands when expanded prop is true', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    expect(screen.getByText('Search Behavior')).toBeInTheDocument();
    expect(screen.getByText('Results Display')).toBeInTheDocument();
    expect(screen.getByText('Performance')).toBeInTheDocument();
    expect(screen.getByText('Content Sources')).toBeInTheDocument();
  });

  test('calls onExpandedChange when header is clicked', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={false}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const header = screen.getByText('Advanced Search Options').closest('div');
    await user.click(header!);

    expect(mockOnExpandedChange).toHaveBeenCalledWith(true);
  });

  test('displays search behavior section by default when expanded', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    expect(screen.getByText('These settings control how your search queries are interpreted and matched against documents.')).toBeInTheDocument();
    expect(screen.getByDisplayValue('simple')).toBeInTheDocument();
    expect(screen.getByLabelText('Enhanced Search Engine')).toBeInTheDocument();
  });

  test('switches between sections correctly', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    // Click on Results Display section
    await user.click(screen.getByText('Results Display'));

    expect(screen.getByText('Control how search results are presented and what information is shown.')).toBeInTheDocument();
    expect(screen.getByLabelText('Show Text Snippets')).toBeInTheDocument();
  });

  test('changes search mode setting', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const searchModeSelect = screen.getByDisplayValue('simple');
    await user.click(searchModeSelect);
    
    const fuzzyOption = screen.getByText('Fuzzy Search');
    await user.click(fuzzyOption);

    expect(mockOnSettingsChange).toHaveBeenCalledWith({ searchMode: 'fuzzy' });
  });

  test('toggles enhanced search setting', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const enhancedSearchSwitch = screen.getByLabelText('Enhanced Search Engine');
    await user.click(enhancedSearchSwitch);

    expect(mockOnSettingsChange).toHaveBeenCalledWith({ useEnhancedSearch: false });
  });

  test('adjusts fuzzy threshold when in fuzzy mode', async () => {
    const user = userEvent.setup();
    const fuzzySettings = { ...mockSettings, searchMode: 'fuzzy' as const };
    
    render(
      <AdvancedSearchPanel
        settings={fuzzySettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const fuzzySlider = screen.getByRole('slider', { name: /fuzzy match threshold/i });
    expect(fuzzySlider).not.toHaveAttribute('disabled');
  });

  test('disables fuzzy threshold when not in fuzzy mode', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const fuzzySlider = screen.getByRole('slider', { name: /fuzzy match threshold/i });
    expect(fuzzySlider).toHaveAttribute('disabled');
  });

  test('shows results display settings correctly', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    await user.click(screen.getByText('Results Display'));

    expect(screen.getByLabelText('Show Text Snippets')).toBeChecked();
    expect(screen.getByDisplayValue('200')).toBeInTheDocument(); // Snippet length
    expect(screen.getByDisplayValue('100')).toBeInTheDocument(); // Results per page
  });

  test('disables snippet length when snippets are disabled', async () => {
    const user = userEvent.setup();
    const settingsWithoutSnippets = { ...mockSettings, includeSnippets: false };
    
    render(
      <AdvancedSearchPanel
        settings={settingsWithoutSnippets}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    await user.click(screen.getByText('Results Display'));

    const snippetLengthSelect = screen.getByLabelText('Snippet Length');
    expect(snippetLengthSelect.closest('div')).toHaveClass('Mui-disabled');
  });

  test('shows content sources settings', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    await user.click(screen.getByText('Content Sources'));

    expect(screen.getByLabelText('Document Content')).toBeChecked();
    expect(screen.getByLabelText('OCR Extracted Text')).toBeChecked();
    expect(screen.getByLabelText('Filenames')).toBeChecked();
  });

  test('shows performance settings with warning', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    await user.click(screen.getByText('Performance'));

    expect(screen.getByText('These settings can affect search speed. Use with caution for large document collections.')).toBeInTheDocument();
    expect(screen.getByRole('slider', { name: /maximum results/i })).toBeInTheDocument();
  });

  test('resets to defaults when reset button is clicked', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    const resetButton = screen.getByText('Reset to Defaults');
    await user.click(resetButton);

    expect(mockOnSettingsChange).toHaveBeenCalledWith({
      useEnhancedSearch: true,
      searchMode: 'simple',
      includeSnippets: true,
      snippetLength: 200,
      fuzzyThreshold: 0.8,
      resultLimit: 100,
      includeOcrText: true,
      includeFileContent: true,
      includeFilenames: true,
      boostRecentDocs: false,
      enableAutoCorrect: true,
    });
  });

  test('shows save preset dialog when save preset is clicked', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
        onSavePreset={mockOnSavePreset}
      />
    );

    const saveButton = screen.getByText('Save Preset');
    await user.click(saveButton);

    expect(screen.getByText('Save Current Settings as Preset')).toBeInTheDocument();
    expect(screen.getByLabelText('Preset Name')).toBeInTheDocument();
  });

  test('saves preset with valid name', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
        onSavePreset={mockOnSavePreset}
      />
    );

    await user.click(screen.getByText('Save Preset'));
    
    const nameInput = screen.getByLabelText('Preset Name');
    await user.type(nameInput, 'My Custom Preset');
    
    const saveButton = screen.getByRole('button', { name: 'Save' });
    await user.click(saveButton);

    expect(mockOnSavePreset).toHaveBeenCalledWith('My Custom Preset', mockSettings);
  });

  test('shows preset selector when presets are available', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
        availablePresets={mockPresets}
        onLoadPreset={mockOnLoadPreset}
      />
    );

    expect(screen.getByLabelText('Load Preset')).toBeInTheDocument();
  });

  test('loads preset when selected', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
        availablePresets={mockPresets}
        onLoadPreset={mockOnLoadPreset}
      />
    );

    const presetSelect = screen.getByLabelText('Load Preset');
    await user.click(presetSelect);
    
    const fastSearchOption = screen.getByText('Fast Search');
    await user.click(fastSearchOption);

    expect(mockOnLoadPreset).toHaveBeenCalledWith(mockPresets[0].settings);
  });

  test('shows enhanced search badge when enabled', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={false}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    // Badge should be visible (not invisible) when enhanced search is enabled
    const badge = screen.getByText('Advanced Search Options').closest('div')?.querySelector('[class*="MuiBadge"]');
    expect(badge).toBeInTheDocument();
  });

  test('hides badge when enhanced search is disabled', () => {
    const settingsWithoutEnhanced = { ...mockSettings, useEnhancedSearch: false };
    
    render(
      <AdvancedSearchPanel
        settings={settingsWithoutEnhanced}
        onSettingsChange={mockOnSettingsChange}
        expanded={false}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    // Badge should be invisible when enhanced search is disabled
    const badge = screen.getByText('Advanced Search Options').closest('div')?.querySelector('[class*="MuiBadge"]');
    expect(badge).toBeInTheDocument(); // Badge element exists but should be invisible
  });

  test('cancels preset save when cancel is clicked', async () => {
    const user = userEvent.setup();
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
        onSavePreset={mockOnSavePreset}
      />
    );

    await user.click(screen.getByText('Save Preset'));
    
    const cancelButton = screen.getByText('Cancel');
    await user.click(cancelButton);

    expect(screen.queryByText('Save Current Settings as Preset')).not.toBeInTheDocument();
  });

  test('shows correct search mode descriptions', () => {
    render(
      <AdvancedSearchPanel
        settings={mockSettings}
        onSettingsChange={mockOnSettingsChange}
        expanded={true}
        onExpandedChange={mockOnExpandedChange}
      />
    );

    expect(screen.getByText('Basic keyword matching with stemming')).toBeInTheDocument();
  });
});