import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Button, Card, Checkbox, Col, Empty, Form, Input, Popconfirm, Progress, Row, Select, Space, Switch, Tag } from 'antd';
import { CalendarOutlined, InboxOutlined, PlusOutlined, SearchOutlined, TeamOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import { useNavigate } from 'react-router-dom';
import api from '../../api';
import { message } from '../../ui/app-message';
import ExamFormModal from './ExamFormModal';
import { selectAllExamIds, toggleExamSelection } from './selection';
import type { ClassOption, ExamFormValues, ExamItem } from './types';
import { EXAM_TYPE_OPTIONS } from './types';
import './style.css';

const ExamsPage: React.FC = () => {
  const navigate = useNavigate();
  const [form] = Form.useForm<ExamFormValues>();
  const [data, setData] = useState<ExamItem[]>([]);
  const [classes, setClasses] = useState<ClassOption[]>([]);
  const [loading, setLoading] = useState(false);
  const [batchLoading, setBatchLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);
  const [keyword, setKeyword] = useState('');
  const [examType, setExamType] = useState<string>();
  const [classId, setClassId] = useState<number>();
  const [showArchived, setShowArchived] = useState(false);
  const [selectedExamIds, setSelectedExamIds] = useState<number[]>([]);

  const loadClasses = useCallback(async () => {
    const result = await api.get<ClassOption[]>('/classes');
    setClasses(result ?? []);
  }, []);

  const loadExams = useCallback(async () => {
    setSelectedExamIds([]);
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (keyword.trim()) params.set('keyword', keyword.trim());
      if (examType) params.set('examType', examType);
      if (classId) params.set('classId', String(classId));
      params.set('isArchived', String(showArchived));
      const result = await api.get<ExamItem[]>(`/exams?${params.toString()}`);
      setData(result ?? []);
    } catch (error) {
      message.error((error as { message?: string })?.message || '加载考试失败');
    } finally {
      setLoading(false);
    }
  }, [classId, examType, keyword, showArchived]);

  useEffect(() => {
    void loadClasses().catch((error: { message?: string }) => message.error(error?.message || '加载班级失败'));
  }, [loadClasses]);

  useEffect(() => {
    const timer = window.setTimeout(() => void loadExams(), 200);
    return () => window.clearTimeout(timer);
  }, [loadExams]);

  const classOptions = useMemo(
    () => classes.map((item) => ({ value: item.id, label: item.name })),
    [classes],
  );

  const openCreate = () => {
    form.resetFields();
    form.setFieldValue('examDate', dayjs());
    setModalOpen(true);
  };

  const submit = async () => {
    try {
      const values = await form.validateFields();
      setSaving(true);
      const payload = { ...values, examDate: values.examDate.format('YYYY-MM-DD') };
      await api.post('/exams', payload);
      message.success('考试已创建');
      setModalOpen(false);
      await loadExams();
    } catch (error) {
      if ((error as { errorFields?: unknown[] }).errorFields) return;
      message.error((error as { message?: string })?.message || '保存失败');
    } finally {
      setSaving(false);
    }
  };

  const changeArchiveStatus = async (exam: ExamItem, archive: boolean) => {
    try {
      await api.put(`/exams/${exam.id}/${archive ? 'archive' : 'restore'}`);
      message.success(archive ? '考试已归档' : '考试已恢复');
      await loadExams();
    } catch (error) {
      message.error((error as { message?: string })?.message || '操作失败');
    }
  };

  const allCurrentSelected = data.length > 0 && selectedExamIds.length === data.length;
  const partiallySelected = selectedExamIds.length > 0 && !allCurrentSelected;

  const toggleSelectAll = (checked: boolean) => {
    setSelectedExamIds(selectAllExamIds(data.map((exam) => exam.id), checked));
  };

  const changeArchiveView = (checked: boolean) => {
    setSelectedExamIds([]);
    setShowArchived(checked);
  };

  const batchChangeArchiveStatus = async (archive: boolean) => {
    if (selectedExamIds.length === 0 || batchLoading) return;
    setBatchLoading(true);
    try {
      if (archive) {
        const result = await api.put<{ archived: number; skipped: number }>('/exams/batch-archive', {
          ids: selectedExamIds,
        });
        message.success(
          `已归档 ${result.archived} 场考试${result.skipped ? `，跳过 ${result.skipped} 场` : ''}`,
        );
      } else {
        const result = await api.put<{ restored: number; skipped: number }>('/exams/batch-restore', {
          ids: selectedExamIds,
        });
        message.success(
          `已恢复 ${result.restored} 场考试${result.skipped ? `，跳过 ${result.skipped} 场` : ''}`,
        );
      }
      setSelectedExamIds([]);
      await loadExams();
    } catch (error) {
      message.error((error as { message?: string })?.message || '批量操作失败');
    } finally {
      setBatchLoading(false);
    }
  };

  return (
    <div className="exam-page">
      <div className="exam-toolbar">
        <Space wrap>
          <Input value={keyword} onChange={(event) => setKeyword(event.target.value)} prefix={<SearchOutlined />} placeholder="搜索考试名称" allowClear />
          <Select value={examType} onChange={setExamType} options={EXAM_TYPE_OPTIONS} placeholder="考试类型" allowClear style={{ width: 140 }} />
          <Select value={classId} onChange={setClassId} options={classOptions} placeholder="考试班级" allowClear showSearch optionFilterProp="label" style={{ width: 180 }} />
        </Space>
        <Space wrap>
          <Checkbox
            checked={allCurrentSelected}
            indeterminate={partiallySelected}
            disabled={data.length === 0 || loading || batchLoading}
            onChange={(event) => toggleSelectAll(event.target.checked)}
          >
            全选当前结果
          </Checkbox>
          <Popconfirm
            title={showArchived ? '确认恢复选中的考试？' : '确认归档选中的考试？'}
            description={
              showArchived
                ? `将恢复选中的 ${selectedExamIds.length} 场考试。`
                : `将归档选中的 ${selectedExamIds.length} 场考试，归档后成绩将变为只读。`
            }
            disabled={selectedExamIds.length === 0 || batchLoading}
            onConfirm={() => void batchChangeArchiveStatus(!showArchived)}
          >
            <Button
              danger={!showArchived}
              loading={batchLoading}
              disabled={selectedExamIds.length === 0}
            >
              {showArchived ? '批量恢复' : '批量归档'}
            </Button>
          </Popconfirm>
          <span className="exam-archive-toggle">
            <InboxOutlined />
            归档
            <Switch size="small" checked={showArchived} onChange={changeArchiveView} />
          </span>
          {!showArchived ? (
            <Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>创建考试</Button>
          ) : null}
        </Space>
      </div>

      {data.length === 0 && !loading ? (
        <div className="exam-empty"><Empty description="暂无考试" /></div>
      ) : (
        <Row gutter={[16, 16]}>
          {data.map((exam) => {
            const percent = exam.totalStudents === 0 ? 0 : Math.round((exam.enteredScores / exam.totalStudents) * 100);
            return (
              <Col key={exam.id} xs={24} sm={12} xl={8} xxl={6}>
                <Card
                  className={`exam-card${selectedExamIds.includes(exam.id) ? ' exam-card-selected' : ''}`}
                  loading={loading}
                  title={(
                    <Space>
                      <Checkbox
                        aria-label={`选择考试 ${exam.examName}`}
                        checked={selectedExamIds.includes(exam.id)}
                        disabled={batchLoading}
                        onChange={(event) => {
                          setSelectedExamIds((current) =>
                            toggleExamSelection(current, exam.id, event.target.checked),
                          );
                        }}
                      />
                      <Tag color="blue">{exam.examType}</Tag>
                      <span>{exam.examName}</span>
                    </Space>
                  )}
                  extra={<Tag color={exam.status === 'archived' ? 'default' : 'green'}>{exam.status === 'archived' ? '已归档' : '成绩录入'}</Tag>}
                  actions={[
                    <span key="detail" onClick={() => navigate(`/exams/${exam.id}`)}>查看成绩</span>,
                    exam.status === 'archived' ? (
                      <Popconfirm
                        key="restore"
                        title="确认恢复该考试？"
                        onConfirm={() => changeArchiveStatus(exam, false)}
                      >
                        <span>恢复</span>
                      </Popconfirm>
                    ) : (
                      <Popconfirm
                        key="archive"
                        title="确认归档该考试？"
                        description={`当前已录入 ${exam.enteredScores}/${exam.totalStudents} 人，归档后成绩将变为只读。`}
                        onConfirm={() => changeArchiveStatus(exam, true)}
                      >
                        <span>归档</span>
                      </Popconfirm>
                    ),
                  ]}
                >
                  <div className="exam-meta"><span>科目</span><strong>{exam.subject}</strong></div>
                  <div className="exam-meta"><span><TeamOutlined /> 班级</span><strong>{exam.className}</strong></div>
                  <div className="exam-meta"><span><CalendarOutlined /> 日期</span><strong>{exam.examDate}</strong></div>
                  <div className="exam-progress"><div><span>成绩录入</span><strong>{exam.enteredScores}/{exam.totalStudents}</strong></div><Progress percent={percent} size="small" /></div>
                </Card>
              </Col>
            );
          })}
        </Row>
      )}

      <ExamFormModal open={modalOpen} editing={false} saving={saving} form={form} classes={classes} onCancel={() => setModalOpen(false)} onSubmit={() => void submit()} />
    </div>
  );
};

export default ExamsPage;
