import { act, fireEvent, render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { resetStore } from '../test/storeTestUtils';
import { useStore } from '../store/useStore';
import { FrameTimeline } from './FrameTimeline';

describe('FrameTimeline', () => {
  beforeEach(() => {
    resetStore();
    vi.useRealTimers();
  });

  it('renders empty state when no frames are loaded', () => {
    render(<FrameTimeline />);

    expect(screen.getByText('暂无帧数据')).toBeInTheDocument();
    expect(screen.getByText('0')).toBeInTheDocument();
  });

  it('changes the current frame through thumbnails and range input', () => {
    useStore.setState({
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
        { id: 'f3', projectId: 'p1', index: 2, url: '/3.jpg', width: 640, height: 360 },
      ],
    });

    render(<FrameTimeline />);
    fireEvent.click(screen.getByAltText('frame-1'));
    expect(useStore.getState().currentFrameIndex).toBe(1);

    fireEvent.change(screen.getByRole('slider'), { target: { value: '3' } });
    expect(useStore.getState().currentFrameIndex).toBe(2);
  });

  it('shows current and total timeline time based on project fps', () => {
    useStore.setState({
      currentProject: { id: 'p1', name: 'P', status: 'ready', parse_fps: 10 },
      currentFrameIndex: 1,
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
        { id: 'f3', projectId: 'p1', index: 2, url: '/3.jpg', width: 640, height: 360 },
      ],
    });

    render(<FrameTimeline />);

    expect(screen.getAllByText('00:00.10').length).toBeGreaterThan(0);
    expect(screen.getAllByText('00:00.20').length).toBeGreaterThan(0);
  });

  it('marks propagated frames as light-blue progress bar segments', () => {
    useStore.setState({
      currentFrameIndex: 1,
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
        { id: 'f3', projectId: 'p1', index: 2, url: '/3.jpg', width: 640, height: 360 },
      ],
      masks: [
        { id: 'm1', frameId: 'f2', pathData: 'M 0 0 Z', label: 'Draft', color: '#06b6d4' },
        {
          id: 'm2',
          frameId: 'f3',
          annotationId: '9',
          pathData: 'M 0 0 Z',
          label: 'Saved',
          color: '#22c55e',
          metadata: { source: 'sam2.1_hiera_tiny_propagation' },
        },
        { id: 'outside', frameId: 'other-frame', pathData: 'M 0 0 Z', label: 'Other', color: '#fff' },
      ],
    });

    render(<FrameTimeline />);

    expect(screen.getByText('自动传播 1 帧')).toBeInTheDocument();
    expect(screen.queryByTestId('current-frame-line')).not.toBeInTheDocument();
    expect(screen.getAllByTestId('propagated-frame-segment')).toHaveLength(1);
    expect(screen.getByTestId('propagated-frame-segment').className).toContain('bg-sky-200');
    expect(screen.queryByLabelText('跳转到已编辑帧 3')).not.toBeInTheDocument();
  });

  it('changes frames with left and right arrow keys without leaving bounds', () => {
    useStore.setState({
      currentFrameIndex: 1,
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
        { id: 'f3', projectId: 'p1', index: 2, url: '/3.jpg', width: 640, height: 360 },
      ],
    });

    render(<FrameTimeline />);
    fireEvent.keyDown(window, { key: 'ArrowRight' });
    expect(useStore.getState().currentFrameIndex).toBe(2);

    fireEvent.keyDown(window, { key: 'ArrowRight' });
    expect(useStore.getState().currentFrameIndex).toBe(2);

    fireEvent.keyDown(window, { key: 'ArrowLeft' });
    expect(useStore.getState().currentFrameIndex).toBe(1);
  });

  it('does not change frames while typing in editable fields', () => {
    useStore.setState({
      currentFrameIndex: 1,
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
        { id: 'f3', projectId: 'p1', index: 2, url: '/3.jpg', width: 640, height: 360 },
      ],
    });

    render(
      <>
        <input aria-label="annotation-name" />
        <FrameTimeline />
      </>,
    );
    fireEvent.keyDown(screen.getByLabelText('annotation-name'), { key: 'ArrowRight' });

    expect(useStore.getState().currentFrameIndex).toBe(1);
  });

  it('plays forward using the project parse fps and stops at the end', () => {
    vi.useFakeTimers();
    useStore.setState({
      currentProject: { id: 'p1', name: 'P', status: 'ready', parse_fps: 10 },
      frames: [
        { id: 'f1', projectId: 'p1', index: 0, url: '/1.jpg', width: 640, height: 360 },
        { id: 'f2', projectId: 'p1', index: 1, url: '/2.jpg', width: 640, height: 360 },
      ],
    });

    const { container } = render(<FrameTimeline />);
    fireEvent.click(container.querySelector('button')!);

    act(() => {
      vi.advanceTimersByTime(100);
    });

    expect(useStore.getState().currentFrameIndex).toBe(1);

    act(() => {
      vi.advanceTimersByTime(100);
    });

    expect(screen.getByText('播放序列 (F5)')).toBeInTheDocument();
  });
});
