import { blobToBase64 } from "@/utils/file";
import { ElMessage } from "element-plus";
import { $ajax } from ".";
import { sha256 } from "js-sha256";
import axios, { Canceler } from "axios";

// 分块文件检查
export function fileCheck(query: any) {
  return $ajax({
    url: "/api/file/chunk/check",
    type: "get",
    params: query,
  });
}
// 文件合并
export function fileMerge(data: any) {
  return $ajax({
    url: "/api/file/chunk/merge",
    type: "post",
    params: data,
  });
}

export function fileUnzip(data: {
  category_id: number;
  file_name: string;
  file_hash: string;
}) {
  return $ajax({
    url: "/api/file/chunk/unzip",
    type: "post",
    params: data,
  });
}

var CancelToken = axios.CancelToken;

// 分块文件上传
export function fileUpload(
  data: any,
  onProgressChange?: (progressEvent: {
    loaded: number;
    total: number;
    [key: string]: any;
  }) => void
) {
  const source = CancelToken.source();
  const res = $ajax({
    url: "/api/file/chunk/upload",
    type: "post",
    params: data,
    config: {
      cancelToken: source.token,
      onUploadProgress: onProgressChange,
    },
  });
  return Object.assign(res, { cancel: source.cancel });
}
// 批量获取文件
export function getFiles(query: any) {
  return $ajax({
    url: `/api/files?${query}`,
    type: "get",
  });
}

interface iFileChunkPayload {
  current_data: string; //当前块数据
  current_seq: number; // 当前块序号
  current_size: number; //当前块大小
  file_name: string; //文件名称
  file_hash: string; //文件hash
  total_seq: number; //总序号
  total_size: number; //总大小
}

function splitFileToFileChunks(file: File, chunkSize = 16) {
  const fileChunks: Blob[] = [];
  let slicesize = file.size;
  while (slicesize > chunkSize * 1024 * 1024) {
    const blobPart = file.slice(
      fileChunks.length * chunkSize * 1024 * 1024,
      (fileChunks.length + 1) * chunkSize * 1024 * 1024
    );
    fileChunks.push(blobPart);
    slicesize -= chunkSize * 1024 * 1024;
  }
  if (slicesize > 0) {
    fileChunks.push(
      file.slice(fileChunks.length * chunkSize * 1024 * 1024, file.size)
    );
  }
  return fileChunks;
}

export function handleBigFileUpload(
  file: File,
  onPercentCompleteChange?: (percent: number) => void
) {
  return new Promise<{
    unzip: (category_id: number) => Promise<any>;
    uploadAllFileChunks: Promise<boolean>;
    cancelUpload?: () => void;
  }>((rootResolve, rootReject) => {
    let isCancel = false;
    let __sendingAmount = 0;
    let __total = 0;
    let __sendingIncreasing = false;
    const cancelTokenList: Canceler[] = [];
    let progressLoaded = 0;
    const FILE_SIZE = file.size;

    const fileChunks = splitFileToFileChunks(file);

    const fileReader = new FileReader();
    let fileHash = sha256.create();
    fileReader.onload = function (event: Event) {
      const result = (event!.target! as any).result;
      fileHash.update(result);
      fileHash.update(file.name);
      fileCheck({ file_hash: fileHash.hex() }).then((res: any) => {
        if (!res) return;
        let { is_done, file_info } = res.data;
        if (is_done && file_info) {
          // 上传完成
          ElMessage({
            message: "上传成功",
            type: "success",
          });
          rootResolve({
            unzip: (category_id: number) =>
              fileUnzip({
                category_id,
                file_hash: res.data.file_hash,
                file_name: file_info.name,
              }),
            uploadAllFileChunks: Promise.resolve(true),
          });
          return;
        }

        const uploadAllFileChunks = new Promise<boolean>(
          (resolveAllFileUpload, rejectAllFileUpload) => {
            //  上传文件
            function uploadFileChunk(
              fileChunkPayload: iFileChunkPayload,
              numOfFileChunks: number
            ) {
              let i = setInterval(() => {
                if (isCancel) {
                  clearInterval(i);
                  return;
                }
                if (__sendingAmount - __total === 0) {
                  __sendingIncreasing = true;
                }
                if (__sendingAmount - __total > 6) {
                  __sendingIncreasing = false;
                }
                if (__sendingIncreasing) {
                  clearInterval(i);
                  __sendingAmount += 1;
                  let lastLoaded = 0;
                  const afterFileUpload = fileUpload(
                    fileChunkPayload,
                    (progressEvent) => {
                      progressLoaded -= lastLoaded;
                      lastLoaded =
                        (progressEvent.loaded / progressEvent.total) *
                        fileChunkPayload.current_size;
                      progressLoaded +=
                        (progressEvent.loaded / progressEvent.total) *
                        fileChunkPayload.current_size;
                      console.log(
                        progressLoaded / FILE_SIZE,
                        "show progressLoaded / FILE_SIZE"
                      );
                      onPercentCompleteChange &&
                        onPercentCompleteChange(progressLoaded / FILE_SIZE);
                    }
                  );
                  cancelTokenList.push(afterFileUpload.cancel);
                  afterFileUpload.then((res) => {
                    if (!res && !isCancel) {
                      ElMessage({
                        message: "上传失败，请重新上传",
                        type: "warning",
                      });
                      rejectAllFileUpload("上传失败，请重新上传");
                      return;
                    }
                    __total += 1;
                    if (__total === fileChunks.length) {
                      onPercentCompleteChange && onPercentCompleteChange(1);
                    }
                    if (__total === numOfFileChunks) {
                      resolveAllFileUpload(true);
                    }
                  });
                }
              }, 500);
            }

            Promise.all(
              fileChunks.map((fileChunk, index) => {
                return blobToBase64(fileChunk).then(
                  (base64FileData: string) => {
                    return uploadFileChunk(
                      {
                        current_data: base64FileData, //当前块数据
                        current_seq: index + 1, // 当前块序号
                        current_size: fileChunk.size, //当前块大小
                        file_name: file.name, //文件名称
                        file_hash: fileHash.hex(), //文件hash
                        total_seq: fileChunks.length, //总序号
                        total_size: file.size, //总大小
                      },
                      fileChunks.length
                    );
                  }
                );
              })
            );
          }
        );

        rootResolve({
          uploadAllFileChunks,
          unzip: (category_id: number) => {
            return uploadAllFileChunks.then(() => {
              return fileUnzip({
                category_id,
                file_hash: fileHash.hex(),
                file_name: file.name,
              });
            });
          },
          cancelUpload: () => {
            isCancel = true;
            cancelTokenList.forEach((cancel) => cancel());
          },
        });
      });
    };
    //读取失败回调
    fileReader.onerror = function (err: any) {
      rootReject();
    };
    fileReader.readAsArrayBuffer(file);
  });
}
