import Taro from "@tarojs/taro";
import { useCallback, useRef, useState } from "react";

export enum PRELOADER_STATUS {
  ERROR = "error",
  LOADING = "loading",
  WAITING = "waiting",
  DONE = "done",
}

const parseUrlName = (url: string) => {
  const regex = /\/([^/]+)\.\w+$/;
  const match = url.match(regex);
  if (match && match.length >= 2) {
    return match[1].split(".")[0];
  } else {
    return "";
  }
};

export function usePreloader(params: {
  list: string[];
  /**
   * 百分比保留几位小数
   */
  decimals?: number;
  success?: Function;
  error?: Function;
  /**
   * 尝试重连次数
   * @default 3
   */
  retry?: number;
}) {
  const _list = useRef(params.list);
  const _retry = params.retry ?? 3;

  const fileSizeStack = useRef<Map<string, number>>(new Map());

  /**
   * 进度
   */
  const [percent, setPercent] = useState(0);
  const [status, setStatus] = useState<PRELOADER_STATUS>(
    PRELOADER_STATUS.WAITING
  );

  const handlePreload = (url: string, retry = _retry) => {
    return new Promise((res, rej) => {
      Taro.request({
        url,
        responseType: "arraybuffer",
        enableChunked: true,
      })
        .then(() => {
          fileSizeStack.current.set(url, 1);

          if (fileSizeStack.current.size === _list.current.length) {
            setPercent(100);
          }

          res(true);
        })
        .catch((err) => {
          console.log(err);
          if (retry) {
            console.log("尝试重新预加载");
            setTimeout(() => {
              handlePreload(url, retry - 1)
                .then(res)
                .catch(rej);
            }, 2000);
          } else {
            rej(err);
          }
        });
    });
  };

  const resetParams = () => {
    fileSizeStack.current.clear();
    setPercent(0);
  };

  const start = () => {
    if (status === PRELOADER_STATUS.LOADING) return;

    if (status !== PRELOADER_STATUS.WAITING) {
      resetParams();
    }

    setStatus(PRELOADER_STATUS.LOADING);

    const timer = setInterval(() => {
      if (percent < 99) {
        setPercent((num) => num + 1);
      } else {
        clearInterval(timer);
      }
    }, 500);

    Promise.all(_list.current.map((url) => handlePreload(url)))
      .then(() => {
        params.success?.();
        setStatus(PRELOADER_STATUS.DONE);
      })
      .catch((err: Error) => {
        params.error?.(err);
        setStatus(PRELOADER_STATUS.ERROR);
      })
      .finally(() => {
        clearInterval(timer);
      });
  };

  return {
    status,
    percent,
    start,
  };
}
