import { httpApp } from "@/plugins/axiosApp";
import { useTimers } from "@/setups/useTimers";
import { store } from "@/store/store";
import { showLogout } from "@/utils/utils";
import { onUnmounted, Ref, ref, watch } from "vue";

// 不管被请求多少次，interval只需要初始化一次
// useFaceCompare被重复调用，会导致snapId不是全局唯一的问题

type Ret = {
  snapId: Ref<number>;
  doSnap: () => void;
  showSnapResult: (
    fileName: string,
    examRecordDataId: string | number
  ) => Promise<void>;
};
let singleton: Ret | null;
/** 人脸后台Face++比对 */
export function useFaceCompare(): Ret {
  if (singleton) return singleton;

  const { addInterval, addTimeout } = useTimers();

  let initSnapInterval: number;
  let initSnapshotTrialTimes = 0;

  const snapId = ref(0);

  watch(
    () => store.exam.faceCheckEnabled,
    () => {
      if (!store.exam.faceCheckEnabled) return;

      initSnapInterval = addInterval(() => {
        logger({
          cnl: ["server"],
          pgn: "答题页面",
          key: "首次抓拍尝试",
          act: "获取摄像头状态",
        });
        const video = <HTMLVideoElement>document.getElementById("video");
        const videoStartFailed = !video || video.readyState !== 4;
        initSnapshotTrialTimes++;
        if (videoStartFailed && initSnapshotTrialTimes <= 5) {
          logger({
            cnl: ["server"],
            pgn: "答题页面",
            key: "首次抓拍尝试",
            dtl: `进入考试后60秒内-(第${initSnapshotTrialTimes}次尝试)`,
          });
        } else {
          // 超过6次后，强行抓拍，如果抓拍不成功，则会因抓拍不成功而退出。
          clearInterval(initSnapInterval);
          if (videoStartFailed) {
            logger({
              cnl: ["server"],
              pgn: "答题页面",
              key: "首次抓拍尝试",
              dtl: "摄像头没有正常启用-进入考试抓拍",
            });
            $message.error("摄像头没有正常启用");
            showLogout("摄像头没有正常启用-退出");
          } else {
            logger({
              cnl: ["server"],
              pgn: "答题页面",
              key: "首次抓拍尝试",
              dtl: `进入考试后60秒内-(第${initSnapshotTrialTimes}次尝试成功)`,
            });
            doSnap(); // 开启抓拍才在进入考试时抓拍一张
          }
        }
      }, 10 * 1000);
    },
    { immediate: true }
  );

  watch(
    () => store.exam.SNAPSHOT_INTERVAL,
    () => {
      if (store.exam.SNAPSHOT_INTERVAL > 0) {
        // 考务设置抓拍间隔
        addInterval(() => {
          logger({
            cnl: ["server"],
            pgn: "答题页面",
            dtl: "定时抓拍设置interval",
            ext: { SNAPSHOT_INTERVAL: store.exam.SNAPSHOT_INTERVAL },
          });
          doSnap();
        }, store.exam.SNAPSHOT_INTERVAL * 60 * 1000);
      }
    },
    { immediate: true }
  );

  function doSnap() {
    snapId.value = Date.now();
  }

  // 离开此页面时，可能还有心跳请求未返回
  onUnmounted(() => {
    cancelShow && cancelShow.abort();
    singleton && (singleton = null);
  });

  let cancelShow: AbortController;

  async function showSnapResult(
    fileName: string,
    examRecordDataId: string | number
  ) {
    if (!fileName) return; // 交卷后提交照片会得不到照片名称

    try {
      // 给后台10秒的处理时间
      await new Promise((res) => setTimeout(res, 10 * 1000));
      cancelShow = new AbortController();

      // 获取抓拍结果
      const snapRes =
        (
          await httpApp.get(
            "/api/ecs_oe_student/examCaptureQueue/getExamCaptureResult?fileName=" +
              fileName +
              "&examRecordDataId=" +
              examRecordDataId,
            { signal: cancelShow.signal }
          )
        ).data || {};
      if (snapRes.isCompleted) {
        if (snapRes.isStranger) {
          $message.error("请独立完成考试");
        } else if (!snapRes.isPass) {
          $message.error("请调整坐姿，诚信考试");
        }
        // 可能此时已经退出考试了，所以compareResultMap可能为空
        store.exam.compareResultMap?.set(fileName, true);
      } else {
        addTimeout(
          showSnapResult.bind(null, fileName, examRecordDataId),
          20 * 1000
        );
      }
    } catch (e) {
      // $message.error(e instanceof Error ? e.message : "抓拍查询错误");
      logger({ cnl: ["server"], act: "抓拍查询错误", possibleError: e });
      throw e;
    }
  }

  singleton = { snapId, doSnap, showSnapResult };

  return singleton;
}
