import React, { useRef, useState } from 'react';
import { App, Button, Modal, Popconfirm, Space, Table, Upload } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { EyeOutlined, InboxOutlined, UploadOutlined } from '@ant-design/icons';
import api from '../../api';
import { message } from '../../ui/app-message';
import { useApiMutation } from '../../hooks/useApiMutation';
import { usePermission } from '../../hooks/usePermission';
import { getErrorMessage } from '../../utils/error';
import { ATTACHMENT_CATEGORY_OPTIONS, formatFileSize } from './shared';
import type { AttachmentRecord, TabProps } from './shared';

type AttachmentPreview = {
  url: string;
  name: string;
  kind: 'image' | 'pdf';
};

/** 根据文件扩展名决定安全展示方式：图片/PDF 内联预览，其余一律下载 */
function getAttachmentKind(fileName: string, mimeType?: string): 'image' | 'pdf' | 'download' {
  const ext = fileName.split('.').pop()?.toLowerCase() ?? '';
  if (['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'svg'].includes(ext)) return 'image';
  if (ext === 'pdf' || mimeType === 'application/pdf') return 'pdf';
  return 'download';
}

export const AttachmentsTab: React.FC<TabProps & { data: AttachmentRecord[] }> = ({
  data,
  studentId,
}) => {
  const { modal } = App.useApp();
  const { hasPermission } = usePermission();
  const canPurgeArchive = hasPermission('archive:purge');
  const [uploading, setUploading] = useState(false);
  const [preview, setPreview] = useState<AttachmentPreview | null>(null);
  // 预览请求序号：快速点不同行「查看」时，慢的旧响应回来直接丢弃，避免覆盖新预览
  const previewSeqRef = useRef(0);

  const deleteAttachmentMutation = useApiMutation(
    async (attachmentId: number) => api.delete(`/archive/attachments/${attachmentId}`),
    { invalidate: [['archive', studentId]] },
  );
  const purgeAttachmentMutation = useApiMutation(
    async (id: number) => api.delete(`/archive/attachments/${id}/permanent`),
    { invalidate: [['archive', studentId]] },
  );
  const uploadAttachmentMutation = useApiMutation(
    async (formData: FormData) =>
      api.post(`/archive/${studentId}/attachments`, formData),
    { invalidate: [['archive', studentId]] },
  );

  const closePreview = () => {
    previewSeqRef.current += 1; // 关闭后仍在途的旧响应也不再落地
    if (preview?.url) URL.revokeObjectURL(preview.url);
    setPreview(null);
  };

  const openAttachment = async (record: AttachmentRecord) => {
    const seq = ++previewSeqRef.current;
    try {
      const blob = await api.get<Blob>(`/archive/${studentId}/attachments/${record.id}`, {
        responseType: 'blob',
      });
      if (seq !== previewSeqRef.current) return; // 已有更新的查看请求，丢弃本次慢响应
      const kind = getAttachmentKind(record.fileName, record.mimeType);
      const url = URL.createObjectURL(blob);
      if (kind === 'download') {
        // 非内联类型通过 download 属性触发下载，避免以页面同源打开可执行内容
        const a = document.createElement('a');
        a.href = url;
        a.download = record.fileName || 'attachment';
        document.body.appendChild(a);
        a.click();
        a.remove();
        window.setTimeout(() => URL.revokeObjectURL(url), 60_000);
      } else {
        if (preview?.url) URL.revokeObjectURL(preview.url);
        setPreview({ url, name: record.fileName || 'attachment', kind });
      }
    } catch (e: unknown) {
      message.error(getErrorMessage(e, '查看失败'));
    }
  };

  const handleDelete = async (attachmentId: number) => {
    try {
      await deleteAttachmentMutation.mutateAsync(attachmentId);
      message.success('已归档');
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const handlePurge = (record: AttachmentRecord) => {
    modal.confirm({
      title: `永久删除附件「${record.fileName}」？`,
      content: '删除后不可恢复，磁盘上的附件文件将被清除。确定继续？',
      okText: '永久删除',
      okButtonProps: { danger: true },
      cancelText: '取消',
      onOk: async () => {
        try {
          await purgeAttachmentMutation.mutateAsync(record.id);
          message.success('已永久删除（不可恢复）');
        } catch {
          // 错误提示由 useApiMutation 统一处理
        }
      },
    });
  };

  const columns: ColumnsType<AttachmentRecord> = [
    {
      title: '类别',
      dataIndex: 'category',
      render: (v: string) => ATTACHMENT_CATEGORY_OPTIONS.find((o) => o.value === v)?.label || v,
    },
    { title: '文件名', dataIndex: 'fileName' },
    { title: '大小', dataIndex: 'fileSize', render: formatFileSize },
    {
      title: '操作',
      render: (_: unknown, record: AttachmentRecord) => (
        <Space>
          <Button size="small" icon={<EyeOutlined />} onClick={() => openAttachment(record)}>
            查看
          </Button>
          {hasPermission('student:edit') && record.status !== 'archived' ? (
            <Popconfirm title="确定归档该附件？" onConfirm={() => handleDelete(record.id)}>
              <Button size="small" danger icon={<InboxOutlined />}>
                归档
              </Button>
            </Popconfirm>
          ) : null}
          {record.status === 'archived' && canPurgeArchive ? (
            <Button size="small" danger type="link" onClick={() => handlePurge(record)}>
              删除
            </Button>
          ) : null}
        </Space>
      ),
    },
  ];

  return (
    <div>
      {hasPermission('student:edit') ? (
        <Upload
          showUploadList={false}
          customRequest={async (options) => {
            const formData = new FormData();
            formData.append(
              'file',
              options.file instanceof File
                ? options.file
                : new File([options.file as Blob], 'attachment'),
            );
            setUploading(true);
            try {
              await uploadAttachmentMutation.mutateAsync(formData);
              message.success('上传成功');
              options.onSuccess?.({});
            } catch (e) {
              options.onError?.(e instanceof Error ? e : new Error('上传失败'));
            } finally {
              setUploading(false);
            }
          }}
        >
          <Button icon={<UploadOutlined />} loading={uploading}>
            上传附件
          </Button>
        </Upload>
      ) : null}
      <Table<AttachmentRecord> scroll={{ x: 'max-content' }}
        columns={columns}
        dataSource={data}
        rowKey="id"
        rowClassName={(record) => (record.status === 'archived' ? 'archived-row' : '')}
        pagination={{
          defaultPageSize: 15,
          showSizeChanger: true,
          pageSizeOptions: [15, 30, 50],
        }}
        style={{ marginTop: 16 }}
      />
      <Modal
        title={preview?.name}
        open={!!preview}
        footer={null}
        onCancel={closePreview}
        width={preview?.kind === 'pdf' ? 900 : undefined}
        destroyOnHidden
      >
        {preview?.kind === 'image' ? (
          <img src={preview.url} alt={preview.name} style={{ width: '100%' }} />
        ) : preview?.kind === 'pdf' ? (
          <iframe
            src={preview.url}
            title={preview.name}
            sandbox=""
            style={{ width: '100%', height: '70vh', border: 'none' }}
          />
        ) : null}
      </Modal>
    </div>
  );
};
