import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { Learning } from '@/pages/Learning';
import { MemoryRouter } from 'react-router-dom';

const fetchLearningCoursesMock = vi.hoisted(() => vi.fn());
const fetchMyLearningCoursesMock = vi.hoisted(() => vi.fn());
const listInstalledLearningCoursesMock = vi.hoisted(() => vi.fn());
const downloadLearningCourseMock = vi.hoisted(() => vi.fn());
const startLearningGenerationMock = vi.hoisted(() => vi.fn());
const fetchLearningGenerationMock = vi.hoisted(() => vi.fn());
const finalizeLearningGenerationMock = vi.hoisted(() => vi.fn());
const cancelLearningGenerationMock = vi.hoisted(() => vi.fn());
const resumeLearningGenerationMock = vi.hoisted(() => vi.fn());
const transcribeLearningSpeechMock = vi.hoisted(() => vi.fn());

vi.mock('@/lib/learning', () => ({
  fetchLearningCourses: fetchLearningCoursesMock,
  fetchMyLearningCourses: fetchMyLearningCoursesMock,
  listInstalledLearningCourses: listInstalledLearningCoursesMock,
  downloadLearningCourse: downloadLearningCourseMock,
  startLearningGeneration: startLearningGenerationMock,
  fetchLearningGeneration: fetchLearningGenerationMock,
  finalizeLearningGeneration: finalizeLearningGenerationMock,
  cancelLearningGeneration: cancelLearningGenerationMock,
  resumeLearningGeneration: resumeLearningGenerationMock,
  transcribeLearningSpeech: transcribeLearningSpeechMock,
}));

describe('Learning page', () => {
  beforeEach(() => {
    fetchLearningCoursesMock.mockReset();
    fetchMyLearningCoursesMock.mockReset();
    listInstalledLearningCoursesMock.mockReset();
    downloadLearningCourseMock.mockReset();
    startLearningGenerationMock.mockReset();
    fetchLearningGenerationMock.mockReset();
    finalizeLearningGenerationMock.mockReset();
    cancelLearningGenerationMock.mockReset();
    resumeLearningGenerationMock.mockReset();
    transcribeLearningSpeechMock.mockReset();
    window.localStorage.clear();
    listInstalledLearningCoursesMock.mockResolvedValue([]);
    fetchMyLearningCoursesMock.mockResolvedValue([]);
  });

  it('renders published courses returned by Works Square', async () => {
    fetchLearningCoursesMock.mockResolvedValue([{
      id: 'course-1',
      origin: 'ops_large',
      status: 'published',
      title: 'Python 基础入门',
      summary: '通过互动讲解掌握 Python。',
      language: 'zh-CN',
      contentHash: 'a'.repeat(64),
      archiveSha256: 'b'.repeat(64),
      archiveBytes: 1024,
      formatVersion: 1,
      minPlayerVersion: '1.0.0',
      sceneCount: 10,
      capabilities: { sceneKinds: ['slide', 'interactive', 'quiz'], hasAudio: false, hasWhiteboard: true, hasAgent: true },
      createdAt: '2026-08-16T00:00:00Z',
      publishedAt: '2026-08-16T00:00:00Z',
    }]);

    render(<MemoryRouter><Learning /></MemoryRouter>);

    expect(screen.getByRole('status')).toHaveTextContent('正在读取课程');
    expect(await screen.findByTestId('learning-course-course-1')).toHaveTextContent('Python 基础入门');
    expect(screen.getByText('10 个学习场景')).toBeInTheDocument();
  });

  it('shows a retryable error state', async () => {
    fetchLearningCoursesMock.mockRejectedValue(new Error('连接失败'));

    render(<MemoryRouter><Learning /></MemoryRouter>);

    await waitFor(() => expect(screen.getByRole('alert')).toHaveTextContent('连接失败'));
    expect(screen.getByRole('button', { name: '重试' })).toBeEnabled();
  });

  it('opens the full single-course workbench only from the generate route', async () => {
    fetchLearningCoursesMock.mockResolvedValue([]);
    render(<MemoryRouter initialEntries={['/learning?generate=1']}><Learning /></MemoryRouter>);
    await screen.findByText('暂时还没有已发布课程');

    expect(screen.getByRole('dialog')).toHaveTextContent('今天想学会什么？');
    expect(screen.getByLabelText('课程需求')).toBeEnabled();
    expect(screen.getByRole('button', { name: '后台生成' })).toBeDisabled();
    expect(screen.getByRole('button', { name: '联网搜索' })).toHaveAttribute('aria-pressed', 'false');
    expect(screen.getByRole('button', { name: '语音讲解' })).toHaveAttribute('aria-pressed', 'true');
    expect(screen.getByRole('button', { name: '互动模式' })).toHaveAttribute('aria-pressed', 'true');
    expect(screen.getByRole('button', { name: '职教任务' })).toBeInTheDocument();
    expect(screen.getByRole('button', { name: '语音输入' })).toBeInTheDocument();
    expect(screen.queryByText(/供应商选择/)).not.toBeInTheDocument();
  });

  it('submits every canonical option explicitly to the background job', async () => {
    fetchLearningCoursesMock.mockResolvedValue([]);
    startLearningGenerationMock.mockResolvedValue({
      contractVersion: 2,
      jobId: 'job-1',
      status: 'queued',
      mode: 'single',
      done: false,
    });
    fetchLearningGenerationMock.mockImplementation(() => new Promise(() => undefined));
    render(<MemoryRouter initialEntries={['/learning?generate=1']}><Learning /></MemoryRouter>);

    fireEvent.change(await screen.findByLabelText('课程需求'), { target: { value: '用互动练习教我二次函数' } });
    fireEvent.click(screen.getByRole('button', { name: '联网搜索' }));
    fireEvent.click(screen.getByRole('button', { name: '生成图片' }));
    fireEvent.click(screen.getByRole('button', { name: '职教任务' }));
    fireEvent.click(screen.getByRole('button', { name: '后台生成' }));

    await waitFor(() => expect(startLearningGenerationMock).toHaveBeenCalledWith({
      requirement: '用互动练习教我二次函数',
      enableWebSearch: true,
      enableImageGeneration: true,
      enableVideoGeneration: false,
      enableTTS: true,
      interactiveMode: true,
      taskEngineMode: true,
    }, []));
  });

  it('renders the course plaza without adding another sidebar', async () => {
    fetchLearningCoursesMock.mockResolvedValue([]);

    render(<MemoryRouter><Learning /></MemoryRouter>);

    await screen.findByText('暂时还没有已发布课程');
    expect(screen.getByRole('region', { name: '课程广场' })).toBeInTheDocument();
    expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
    expect(screen.queryByRole('complementary')).not.toBeInTheDocument();
  });
});
