import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import UploadTorrent from '../components/upload';
import { Form, Select } from 'antd';

// 模拟 axios
vi.mock('axios');

// 模拟 antd 的 message
vi.mock('antd', async () => {
  const actual = await vi.importActual('antd');
  return {
    ...actual,
    message: {
      success: vi.fn(),
      error: vi.fn(),
    },
  };
});

describe('UploadTorrent 组件', () => {
  const mockCategories = [
    { categoryid: '1', category_name: '电影' },
    { categoryid: '2', category_name: '剧集' },
    { categoryid: '3', category_name: '音乐' },
    { categoryid: '4', category_name: '动漫' },
    { categoryid: '5', category_name: '游戏' },
    { categoryid: '6', category_name: '综艺' },
    { categoryid: '7', category_name: '体育' },
    { categoryid: '8', category_name: '软件' },
    { categoryid: '9', category_name: '学习资料' },
    { categoryid: '10', category_name: '纪录片' },
    { categoryid: '11', category_name: '音乐' },
  ];

  beforeEach(() => {
    vi.clearAllMocks();
    // 模拟 axios.get 返回分类数据
    vi.mocked(axios.get).mockResolvedValueOnce({ data: mockCategories });
  });

  it('应该正确渲染而不崩溃', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      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('应该加载分类数据', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 验证分类下拉框是否渲染了正确的选项
    const categorySelect = screen.getByLabelText('分类');
    expect(categorySelect).toBeInTheDocument();

    // 打开下拉菜单并检查选项
    fireEvent.mouseDown(categorySelect);
    mockCategories.forEach(category => {
      expect(screen.getByText(category.category_name)).toBeInTheDocument();
    });
  });

  it('应该在选择分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"电影"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('电影'));

    // 验证电影相关的字段是否显示
    expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument();
    expect(screen.getByLabelText('地区')).toBeInTheDocument();
    expect(screen.getByLabelText('年份')).toBeInTheDocument();
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('编码格式')).toBeInTheDocument();
    expect(screen.getByLabelText('分辨率')).toBeInTheDocument();
  });

  it('应该在选择"剧集"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"剧集"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('剧集'));

    // 验证剧集相关的字段是否显示
    expect(screen.getByLabelText('地区')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
  });

  it('应该在选择"游戏"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"游戏"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('游戏'));

    // 验证游戏相关的字段是否显示
    expect(screen.getByLabelText('平台')).toBeInTheDocument();
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('语言')).toBeInTheDocument();
    expect(screen.getByLabelText('数据类型')).toBeInTheDocument();
  });

  it('应该在选择"综艺"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"综艺"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('综艺'));

    // 验证综艺相关的字段是否显示
    expect(screen.getByLabelText('是否大陆综艺')).toBeInTheDocument();
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
  });

  it('应该在选择"动漫"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"动漫"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('动漫'));

    // 验证动漫相关的字段是否显示
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
    expect(screen.getByLabelText('分辨率')).toBeInTheDocument();
  });

  it('应该在选择"学习资料"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"学习资料"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('学习资料'));

    // 验证学习资料相关的字段是否显示
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
  });

  it('应该在选择"纪录片"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"纪录片"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('纪录片'));

    // 验证纪录片相关的字段是否显示
    expect(screen.getByLabelText('年份')).toBeInTheDocument();
    expect(screen.getByLabelText('视频源')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
  });

  it('应该在选择"音乐"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"音乐"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('音乐'));

    // 验证音乐相关的字段是否显示
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('地区')).toBeInTheDocument();
    expect(screen.getByLabelText('风格')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
  });

  it('应该在选择"软件"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"软件"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('软件'));

    // 验证软件相关的字段是否显示
    expect(screen.getByLabelText('平台')).toBeInTheDocument();
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
  });

  it('应该在选择"体育"分类后显示相应的动态字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"体育"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('体育'));

    // 验证体育相关的字段是否显示
    expect(screen.getByLabelText('类型')).toBeInTheDocument();
    expect(screen.getByLabelText('格式')).toBeInTheDocument();
    expect(screen.getByLabelText('赛事类型')).toBeInTheDocument();
  });

  it('应该在选择分类后正确设置状态', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择"电影"分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('电影'));

    // 验证状态是否正确设置
    // 注意：由于状态是组件内部的，我们需要通过 UI 变化来间接验证
    // 这里我们验证电影相关的字段是否显示
    expect(screen.getByLabelText('字幕/说明')).toBeInTheDocument();
  });

  it('应该在选择种子文件后更新状态', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 模拟文件选择
    const fileInput = screen.getByLabelText('种子文件').querySelector('input');
    const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' });
    fireEvent.change(fileInput, { target: { files: [mockFile] } });

    // 验证文件是否被设置（通过 UI 变化间接验证）
    // 由于我们无法直接访问组件状态，我们可以通过表单验证状态来间接验证
    // 这里我们只是验证文件输入是否正常工作
    expect(fileInput).toBeInTheDocument();
  });

  it('应该在选择封面图片后更新状态', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 模拟图片选择
    const imageInput = screen.getByLabelText('封面图片').querySelector('input');
    const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' });
    fireEvent.change(imageInput, { target: { files: [mockImage] } });

    // 验证图片是否被设置（通过 UI 变化间接验证）
    expect(imageInput).toBeInTheDocument();
  });

  it('应该在表单提交时验证必填字段', async () => {
    render(
      <MemoryRouter>
        <UploadTorrent />
      </MemoryRouter>
    );

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 直接提交表单而不填写任何字段
    const submitButton = screen.getByText('上传种子');
    fireEvent.click(submitButton);

    // 验证错误消息是否显示
    // 注意：由于我们使用了 antd 的 Form，错误消息可能由 antd 内部处理
    // 我们可以通过检查是否有错误提示来验证
    // 这里我们只是验证表单提交被调用
    // 更详细的验证可能需要更复杂的测试设置
  });

  it('应该在填写所有必填字段后成功提交表单', async () => {
    // 模拟 axios.post
    vi.mocked(axios.post).mockResolvedValueOnce({ data: {} });

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

    // 等待分类数据加载
    await waitFor(() => {
      expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/categories');
    });

    // 选择分类
    const categorySelect = screen.getByLabelText('分类');
    fireEvent.mouseDown(categorySelect);
    fireEvent.click(screen.getByText('电影'));

    // 填写标题
    const titleInput = screen.getByLabelText('标题');
    fireEvent.change(titleInput, { target: { value: '测试电影' } });

    // 填写描述
    const descriptionInput = screen.getByLabelText('描述');
    fireEvent.change(descriptionInput, { target: { value: '这是一个测试电影的描述' } });

    // 选择封面图片
    const imageInput = screen.getByLabelText('封面图片').querySelector('input');
    const mockImage = new File(['image content'], 'test.jpg', { type: 'image/jpeg' });
    fireEvent.change(imageInput, { target: { files: [mockImage] } });

    // 选择种子文件
    const fileInput = screen.getByLabelText('种子文件').querySelector('input');
    const mockFile = new File(['torrent content'], 'test.torrent', { type: 'application/x-bittorrent' });
    fireEvent.change(fileInput, { target: { files: [mockFile] } });

    // 填写电影相关字段
    const captionInput = screen.getByLabelText('字幕/说明');
    fireEvent.change(captionInput, { target: { value: '测试字幕' } });

    const regionSelect = screen.getByLabelText('地区');
    fireEvent.mouseDown(regionSelect);
    fireEvent.click(screen.getByText('大陆'));

    const yearInput = screen.getByLabelText('年份');
    fireEvent.change(yearInput, { target: { value: '2023' } });

    const genreSelect = screen.getByLabelText('类型');
    fireEvent.mouseDown(genreSelect);
    fireEvent.click(screen.getByText('动作'));

    const codecFormatSelect = screen.getByLabelText('编码格式');
    fireEvent.mouseDown(codecFormatSelect);
    fireEvent.click(screen.getByText('H.264'));

    const resolutionSelect = screen.getByLabelText('分辨率');
    fireEvent.mouseDown(resolutionSelect);
    fireEvent.click(screen.getByText('1080p'));

    // 提交表单
    const submitButton = screen.getByText('上传种子');
    fireEvent.click(submitButton);

    // 验证 axios.post 是否被调用
    expect(axios.post).toHaveBeenCalledWith(
      'http://localhost:8080/torrent/upload',
      expect.any(FormData),
      {
        headers: { 'Content-Type': 'multipart/form-data' },
        responseType: 'blob',
      }
    );

    // 验证成功消息是否显示
    expect(vi.mocked(message.success)).toHaveBeenCalledWith('上传成功！');
  });
});