import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { FrameExtractionConfigPanel } from '../FrameExtractionConfigPanel';
import {
  FrameExtractionConfig,
  FrameType,
  ImageFormat,
  DEFAULT_FRAME_EXTRACTION_CONFIG,
  FRAME_EXTRACTION_PRESETS
} from '../../../types/frame-extractor';

// Mock Tauri API
vi.mock('@tauri-apps/plugin-dialog', () => ({
  open: vi.fn(),
}));

describe('FrameExtractionConfigPanel', () => {
  const mockOnConfigChange = vi.fn();
  const mockOnApplyPreset = vi.fn();

  const defaultProps = {
    config: DEFAULT_FRAME_EXTRACTION_CONFIG,
    onConfigChange: mockOnConfigChange,
    onApplyPreset: mockOnApplyPreset,
    presets: FRAME_EXTRACTION_PRESETS,
  };

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

  it('renders configuration panel with all sections', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    expect(screen.getByText('提取配置')).toBeInTheDocument();
    expect(screen.getByText('预设配置')).toBeInTheDocument();
    expect(screen.getByText('提取类型')).toBeInTheDocument();
    expect(screen.getByText('输出格式')).toBeInTheDocument();
    expect(screen.getByText('图片质量')).toBeInTheDocument();
    expect(screen.getByText('输出尺寸')).toBeInTheDocument();
    expect(screen.getByText('输出目录')).toBeInTheDocument();
    expect(screen.getByText('文件名模式')).toBeInTheDocument();
  });

  it('displays preset configurations', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    FRAME_EXTRACTION_PRESETS.forEach(preset => {
      expect(screen.getByText(preset.name)).toBeInTheDocument();
      expect(screen.getByText(preset.description)).toBeInTheDocument();
    });
  });

  it('calls onApplyPreset when preset is clicked', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const firstPreset = FRAME_EXTRACTION_PRESETS[0];
    const presetButton = screen.getByText(firstPreset.name);
    
    fireEvent.click(presetButton);
    
    expect(mockOnApplyPreset).toHaveBeenCalledWith(firstPreset.id);
  });

  it('displays frame type options', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    expect(screen.getByText('第一帧')).toBeInTheDocument();
    expect(screen.getByText('最后一帧')).toBeInTheDocument();
    expect(screen.getByText('自定义时间')).toBeInTheDocument();
    expect(screen.getByText('多个时间点')).toBeInTheDocument();
  });

  it('calls onConfigChange when frame type is changed', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const lastFrameButton = screen.getByText('最后一帧');
    fireEvent.click(lastFrameButton);

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        frame_type: FrameType.Last,
        custom_time: undefined,
        time_points: undefined,
      })
    );
  });

  it('shows custom time input when Custom frame type is selected', () => {
    const customConfig: FrameExtractionConfig = {
      ...DEFAULT_FRAME_EXTRACTION_CONFIG,
      frame_type: FrameType.Custom,
      custom_time: 15.5,
    };

    render(
      <FrameExtractionConfigPanel
        {...defaultProps}
        config={customConfig}
      />
    );

    const timeInput = screen.getByDisplayValue('15.5');
    expect(timeInput).toBeInTheDocument();
    expect(timeInput).toHaveAttribute('type', 'number');
  });

  it('shows multiple time points input when Multiple frame type is selected', () => {
    const multipleConfig: FrameExtractionConfig = {
      ...DEFAULT_FRAME_EXTRACTION_CONFIG,
      frame_type: FrameType.Multiple,
    };

    render(
      <FrameExtractionConfigPanel
        {...defaultProps}
        config={multipleConfig}
      />
    );

    expect(screen.getByText('多个时间点')).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/输入时间点，用逗号分隔/)).toBeInTheDocument();
  });

  it('displays image format options', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    Object.values(ImageFormat).forEach(format => {
      expect(screen.getByText(format.toUpperCase())).toBeInTheDocument();
    });
  });

  it('calls onConfigChange when image format is changed', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const pngButton = screen.getByText('PNG');
    fireEvent.click(pngButton);

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        output_format: expect.objectContaining({
          format: ImageFormat.Png,
        }),
      })
    );
  });

  it('updates quality when slider is moved', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const qualitySlider = screen.getByRole('slider');
    fireEvent.change(qualitySlider, { target: { value: '95' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        output_format: expect.objectContaining({
          quality: 95,
        }),
      })
    );
  });

  it('updates output size when width/height inputs change', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const widthInput = screen.getByPlaceholderText('自动');
    fireEvent.change(widthInput, { target: { value: '1280' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        output_size: expect.objectContaining({
          width: 1280,
        }),
      })
    );
  });

  it('updates filename pattern when input changes', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const filenameInput = screen.getByDisplayValue(DEFAULT_FRAME_EXTRACTION_CONFIG.filename_pattern);
    fireEvent.change(filenameInput, { target: { value: '{name}_{timestamp}' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        filename_pattern: '{name}_{timestamp}',
      })
    );
  });

  it('toggles overwrite existing checkbox', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const overwriteCheckbox = screen.getByLabelText('覆盖已存在的文件');
    fireEvent.click(overwriteCheckbox);

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        overwrite_existing: true,
      })
    );
  });

  it('toggles maintain aspect ratio checkbox', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const aspectRatioCheckbox = screen.getByLabelText('保持宽高比');
    fireEvent.click(aspectRatioCheckbox);

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        output_size: expect.objectContaining({
          maintain_aspect_ratio: false,
        }),
      })
    );
  });

  it('handles custom time input changes', () => {
    const customConfig: FrameExtractionConfig = {
      ...DEFAULT_FRAME_EXTRACTION_CONFIG,
      frame_type: FrameType.Custom,
      custom_time: 0,
    };

    render(
      <FrameExtractionConfigPanel
        {...defaultProps}
        config={customConfig}
      />
    );

    const timeInput = screen.getByDisplayValue('0');
    fireEvent.change(timeInput, { target: { value: '25.5' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        custom_time: 25.5,
      })
    );
  });

  it('handles multiple time points input', () => {
    const multipleConfig: FrameExtractionConfig = {
      ...DEFAULT_FRAME_EXTRACTION_CONFIG,
      frame_type: FrameType.Multiple,
    };

    render(
      <FrameExtractionConfigPanel
        {...defaultProps}
        config={multipleConfig}
      />
    );

    const timePointsInput = screen.getByPlaceholderText(/输入时间点，用逗号分隔/);
    fireEvent.change(timePointsInput, { target: { value: '10, 50%, 1000f' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        time_points: [
          { type: 'seconds', value: 10 },
          { type: 'percentage', value: 0.5 },
          { type: 'frame', value: 1000 },
        ],
      })
    );
  });

  it('updates output directory when input changes', () => {
    render(<FrameExtractionConfigPanel {...defaultProps} />);

    const directoryInput = screen.getByPlaceholderText('选择输出目录');
    fireEvent.change(directoryInput, { target: { value: '/new/output/path' } });

    expect(mockOnConfigChange).toHaveBeenCalledWith(
      expect.objectContaining({
        output_directory: '/new/output/path',
      })
    );
  });
});
