import React, { useState, useRef } from 'react';
import { Card, Button, Progress, message } from 'antd';
import { FileOutlined } from '@ant-design/icons';
import SparkMD5 from 'spark-md5';
import { findFile, breakpointContinue, breakpointContinueFinish, removeChunk } from '@/services/kratos/fileUpload';
import './index.less';

interface FormDataItem {
  key: number;
  formData: FormData;
}

/**
 * 断点续传页面
 */
const BreakpointUpload: React.FC = () => {
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [file, setFile] = useState<File | null>(null);
  const [fileMd5, setFileMd5] = useState('');
  const [percentage, setPercentage] = useState(0);
  const [formDataList, setFormDataList] = useState<FormDataItem[]>([]);
  const [waitUpload, setWaitUpload] = useState<FormDataItem[]>([]);
  const [uploading, setUploading] = useState(false);

  // 选择文件
  const handleSelectFile = () => {
    fileInputRef.current?.click();
  };

  // 文件选择处理
  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files?.length) return;

    const selectedFile = files[0];
    const maxSize = 5 * 1024 * 1024; // 5MB

    if (selectedFile.size > maxSize) {
      message.error('请上传小于5MB的文件!');
      return;
    }

    setFile(selectedFile);
    setPercentage(0);

    // 读取文件并计算MD5
    const reader = new FileReader();
    reader.readAsArrayBuffer(selectedFile);
    reader.onload = async (event) => {
      const blob = event.target?.result as ArrayBuffer;
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(blob);
      const md5 = spark.end();
      setFileMd5(md5);

      // 切片
      const sliceSize = 1 * 1024 * 1024; // 1MB per slice
      let start = 0;
      let end = 0;
      let i = 0;
      const slices: FormDataItem[] = [];

      while (end < selectedFile.size) {
        start = i * sliceSize;
        end = Math.min((i + 1) * sliceSize, selectedFile.size);
        const fileSlice = selectedFile.slice(start, end);
        
        const formData = new FormData();
        formData.append('fileMd5', md5);
        formData.append('file', fileSlice);
        formData.append('chunkNumber', String(i));
        formData.append('fileName', selectedFile.name);
        
        slices.push({ key: i, formData });
        i++;
      }

      setFormDataList(slices);

      // 检查已上传的切片
      try {
        const res = await findFile({
          fileName: selectedFile.name,
          fileMd5: md5,
          chunkTotal: slices.length,
        });

        if (res.code === 0) {
          const fileInfo = res.data?.file;
          if (fileInfo?.IsFinish) {
            setWaitUpload([]);
            setPercentage(100);
            message.success('文件已秒传!');
          } else {
            const finishList = fileInfo?.ExaFileChunk || [];
            const needUpload = slices.filter((item) => 
              !finishList.some((fi: any) => fi.FileChunkNumber === item.key)
            );
            setWaitUpload(needUpload);
          }
        }
      } catch (error) {
        setWaitUpload(slices);
      }
    };
  };

  // 上传文件
  const handleUpload = async () => {
    if (!file) {
      message.warning('请先选择文件!');
      return;
    }

    if (percentage === 100) {
      message.success('上传已完成!');
      return;
    }

    setUploading(true);
    let uploadedCount = formDataList.length - waitUpload.length;

    for (const item of waitUpload) {
      item.formData.append('chunkTotal', String(formDataList.length));
      
      // 计算切片MD5
      const fileSlice = item.formData.get('file') as Blob;
      const sliceBuffer = await fileSlice.arrayBuffer();
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(sliceBuffer);
      item.formData.append('chunkMd5', spark.end());

      try {
        const res = await breakpointContinue(item.formData);
        if (res.code === 0) {
          uploadedCount++;
          setPercentage(Math.floor((uploadedCount / formDataList.length) * 100));
        }
      } catch (error) {
        console.error('切片上传失败:', error);
      }
    }

    // 合并文件
    if (uploadedCount === formDataList.length) {
      try {
        const finishRes = await breakpointContinueFinish({
          fileName: file.name,
          fileMd5: fileMd5,
        });

        if (finishRes.code === 0) {
          message.success('上传成功');
          // 删除缓存切片
          await removeChunk({
            fileName: file.name,
            fileMd5: fileMd5,
            filePath: finishRes.data?.filePath,
          });
        }
      } catch (error) {
        message.error('文件合并失败');
      }
    }

    setUploading(false);
  };

  return (
    <div className="breakpoint-container">
      <Card>
        <div className="upload-section">
          <div className="section-title">大文件上传</div>
          <div className="button-container">
            <div className="file-upload-btn" onClick={handleSelectFile}>
              <span>选择文件</span>
              <input
                ref={fileInputRef}
                type="file"
                onChange={handleFileChange}
              />
            </div>
            <Button type="primary" onClick={handleUpload} loading={uploading} disabled={percentage === 100}>
              上传文件
            </Button>
          </div>
          <div className="upload-tip">请上传不超过5MB的文件</div>
        </div>

        {file && (
          <div className="file-list">
            <div className="file-item">
              <FileOutlined className="file-icon" />
              <span className="file-name">{file.name}</span>
              <span className="percentage">{percentage}%</span>
            </div>
            <Progress percent={percentage} showInfo={false} strokeWidth={2} />
          </div>
        )}

        <div className="tips">
          此版本为先行体验功能测试版，样式美化和性能优化正在进行中，上传切片文件和合成的完整文件分别在服务器目录的 breakpointDir 文件夹和 fileDir 文件夹
        </div>
      </Card>
    </div>
  );
};

export default BreakpointUpload;
