import React, { useCallback, useMemo } from 'react';
import { Alert, Button, Card, Descriptions, Empty, Space, Spin, Table, Tag, Tooltip } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { ArrowLeftOutlined, EyeOutlined } from '@ant-design/icons';
import { useNavigate, useParams } from 'react-router';
import api from '../../api';
import EditableCell from '../../components/EditableCell';
import { useViewSensitive } from '../../hooks/useViewSensitive';
import { maskPhone } from '../../utils/sensitive';
import { message } from '../../ui/app-message';
import { useQuery } from '@tanstack/react-query';
import { useApiMutation } from '../../hooks/useApiMutation';
import { validateResponse } from '../../utils/validate';
import { examDetailSchema } from '../../api/schemas';
import { usePermission } from '../../hooks/usePermission';
import type { ExamItem } from './types';
import './style.css';
import { getErrorMessage } from '../../utils/error';

interface ScoreRow {
  id: number;
  studentId: number;
  phone: string;
  name: string;
  score: number | null;
  classAvg: number | null;
  rank: number | null;
}

interface ExamDetail extends ExamItem {
  scores: ScoreRow[];
}

const PhoneCell: React.FC<{ row: ScoreRow }> = ({ row }) => {
  const { hasPermission } = usePermission();
  const reveal = useViewSensitive(row.studentId, '考试管理', hasPermission('log:create'));
  if (!row.phone) return <>-</>;
  return (
    <Space size={4}>
      <span>{maskPhone(row.phone)}</span>
      {hasPermission('log:create') ? (
        <Tooltip title="查看完整手机号">
          <Button
            type="text"
            size="small"
            icon={<EyeOutlined />}
            onClick={() => reveal('手机号', row.phone)}
          />
        </Tooltip>
      ) : null}
    </Space>
  );
};

const ExamDetailPage: React.FC = () => {
  const { id } = useParams();
  const navigate = useNavigate();

  const { data: detail, isLoading, isFetching } = useQuery<ExamDetail | null>({
    queryKey: ['exams', 'detail', id],
    queryFn: async () => {
      try {
        return validateResponse<ExamDetail>(
          examDetailSchema,
          await api.get<ExamDetail>(`/exams/${id}`),
        );
      } catch (error) {
        message.error(getErrorMessage(error, '加载考试失败'));
        return null;
      }
    },
  });
  const loading = isLoading || isFetching;

  const saveScoreMutation = useApiMutation(
    async ({ rowId, score }: { rowId: number; score: number | null }) =>
      api.put(`/exams/${id}/scores/${rowId}`, { score }),
    { invalidate: [['exams', 'detail', id]] },
  );
  const saveScore = useCallback(
    async (row: ScoreRow, value: number | undefined) => {
      try {
        await saveScoreMutation.mutateAsync({ rowId: row.id, score: value ?? null });
        message.success('成绩已保存');
      } catch {
        // 错误提示由 useApiMutation 统一处理
      }
    },
    [saveScoreMutation],
  );

  const columns = useMemo<ColumnsType<ScoreRow>>(() => {
    if (!detail) return [];
    const fixed = [
      {
        title: '手机号*',
        width: 155,
        render: (_: unknown, row: ScoreRow) => <PhoneCell row={row} />,
      },
      { title: '姓名', dataIndex: 'name', width: 100 },
      { title: '考试类型*', width: 110, render: () => detail.examType },
      { title: '考试名称', width: 170, render: () => detail.examName },
      { title: '科目*', width: 90, render: () => detail.subject },
    ];
    return [
      ...fixed,
      {
        title: '成绩*',
        dataIndex: 'score',
        width: 100,
        render: (value: number | null, row: ScoreRow) => (
          detail.status === 'archived' ? (
            value ?? '-'
          ) : (
            <EditableCell<number | undefined>
              value={value ?? undefined}
              editor="money"
              min={0}
              max={999.99}
              permission="exam:view"
              onSave={(next) => saveScore(row, next)}
            >
              {value ?? '-'}
            </EditableCell>
          )
        ),
      },
      {
        title: '班级均分',
        dataIndex: 'classAvg',
        width: 110,
        render: (value: number | null) => value ?? '-',
      },
      {
        title: '排名',
        dataIndex: 'rank',
        width: 80,
        render: (value: number | null) => value ?? '-',
      },
      { title: '考试日期', width: 110, render: () => detail.examDate },
      { title: '关联报读（班级名）', width: 180, render: () => detail.className },
    ];
  }, [detail, saveScore]);

  if (loading && !detail)
    return (
      <div className="exam-detail-loading">
        <Spin size="large" />
      </div>
    );
  if (!detail) return <Empty description="考试不存在或无权访问" />;

  const average = detail.scores.find((row) => row.classAvg !== null)?.classAvg ?? null;
  return (
    <div className="exam-detail-page">
      <div className="exam-detail-header">
        <Space>
          <Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/exams')}>
            返回
          </Button>
          <h2>{detail.examName}</h2>
          {detail.status === 'archived' ? <Tag>已归档</Tag> : null}
        </Space>
      </div>
      {detail.status === 'archived' ? (
        <Alert type="info" showIcon message="该考试已归档，成绩仅供查看。如需继续录入，请先在考试列表中恢复。" />
      ) : null}
      <Card className="exam-summary">
        <Descriptions column={{ xs: 1, sm: 2, lg: 5 }}>
          <Descriptions.Item label="考试类型">{detail.examType}</Descriptions.Item>
          <Descriptions.Item label="科目">{detail.subject}</Descriptions.Item>
          <Descriptions.Item label="考试班级">{detail.className}</Descriptions.Item>
          <Descriptions.Item label="考试日期">{detail.examDate}</Descriptions.Item>
          <Descriptions.Item label="录入进度">
            {detail.enteredScores}/{detail.totalStudents}，均分 {average ?? '-'}
          </Descriptions.Item>
        </Descriptions>
      </Card>
      <Card title="成绩表">
        <Table<ScoreRow>
          columns={columns}
          dataSource={detail.scores}
          rowKey="id"
          loading={loading}
          scroll={{ x: 1310 }}
          pagination={{
            defaultPageSize: 30,
            showSizeChanger: true,
            pageSizeOptions: [30, 50, 100],
          }}
          locale={{ emptyText: <Empty description="暂无学生名单" /> }}
        />
      </Card>
    </div>
  );
};

export default ExamDetailPage;
