<template>
  <div class="my-container">
    <mark-header :showTotalScore="store.isMultiMedia" />
    <div class="tw-flex tw-gap-1">
      <mark-history showSearch showOrder :getHistory="getHistoryTask" />
      <mark-body @error="removeBrokenTask" />
      <mark-board-track
        v-if="store.isTrackMode"
        @submit="saveTaskToServer"
        @allZeroSubmit="allZeroSubmit"
        @unselectiveSubmit="unselectiveSubmit"
      />
      <mark-board-key-board
        v-if="store.shouldShowMarkBoardKeyBoard"
        @submit="saveTaskToServer"
        @allZeroSubmit="allZeroSubmit"
        @unselectiveSubmit="unselectiveSubmit"
      />
      <mark-board-mouse
        v-if="store.shouldShowMarkBoardMouse"
        @submit="saveTaskToServer"
        @allZeroSubmit="allZeroSubmit"
        @unselectiveSubmit="unselectiveSubmit"
      />
    </div>
  </div>
  <AnswerModal />
  <PaperModal />
  <MinimapModal />

  <AllPaperModal />
  <SheetViewModal />
  <SpecialTagModal />
  <ShortCutModal />
  <MarkBoardTrackDialog
    v-if="store.isTrackMode"
    @submit="saveTaskToServer"
    @allZeroSubmit="allZeroSubmit"
    @unselectiveSubmit="unselectiveSubmit"
  />
  <a-spin
    v-if="statusSpinning"
    wrapperClassName="status-spin"
    size="large"
    :spinning="loadingStatusSpinning"
  >
    <div
      style="height: 100vh"
      class="tw-text-8xl tw-flex tw-items-center tw-justify-center tw-text-red-500"
      data-test="status-spin"
    >
      {{ store.getStatusValueName }}
    </div>
  </a-spin>
</template>

<script setup lang="ts">
import { onMounted, watch, h, nextTick } from "vue";
import {
  clearMarkTask,
  getGroup,
  getSetting,
  getStatus,
  getTask,
  saveTask,
  updateUISetting,
  doUnselectiveType,
} from "@/api/markPage";
import { store } from "@/store/store";
import MarkHeader from "./MarkHeader.vue";
import MarkBody from "./MarkBody.vue";
import { useTimers } from "@/setups/useTimers";
import MarkHistory from "./MarkHistory.vue";
import MarkBoardTrack from "./MarkBoardTrack.vue";
import type { Question, Task } from "@/types";
import MarkBoardKeyBoard from "./MarkBoardKeyBoard.vue";
import MarkBoardMouse from "./MarkBoardMouse.vue";
import { debounce, isEmpty, isNumber } from "lodash-es";
import { message, Modal } from "ant-design-vue";
import AnswerModal from "./AnswerModal.vue";
import PaperModal from "./PaperModal.vue";
import MinimapModal from "./MinimapModal.vue";
import AllPaperModal from "./AllPaperModal.vue";
import SheetViewModal from "./SheetViewModal.vue";
import SpecialTagModal from "./SpecialTagModal.vue";
import ShortCutModal from "./ShortCutModal.vue";
import { addFileServerPrefixToTask, preDrawImage } from "@/utils/utils";
import { getPaper } from "@/api/jsonMark";
import EventBus from "@/plugins/eventBus";
import { getHistoryTask } from "@/api/markPage";
import MarkBoardTrackDialog from "./MarkBoardTrackDialog.vue";

const { addInterval, addTimeout } = useTimers();

//#region status spinning
/** 试评、正评的页面提示 */
let statusSpinning = $ref(true);
/** 是否还在加载statusValue */
let loadingStatusSpinning = $ref(true);

watch(
  () => store.setting.statusValue,
  () => {
    if (store.setting.statusValue) {
      loadingStatusSpinning = false;
      addTimeout(() => (statusSpinning = false), 3000);
    }
  }
);

//#endregion

async function updateMarkTask() {
  await clearMarkTask();
}

async function updateSetting() {
  const settingRes = await getSetting();
  // 初次使用时，重置并初始化uisetting
  if (isEmpty(settingRes.data.uiSetting)) {
    settingRes.data.uiSetting = {
      "answer.paper.scale": 1,
      "score.board.collapse": false,
      "normal.mode": "keyboard",
      "score.fontSize.scale": 1,
      "paper.modal": false,
      "answer.modal": false,
      "minimap.modal": false,
      "specialTag.modal": false,
      "shortCut.modal": false,
    };
  }
  store.setting = settingRes.data;
  if (store.setting.subject?.answerUrl) {
    store.setting.subject.answerUrl =
      store.setting.fileServer + store.setting.subject?.answerUrl;
  }
  if (store.setting.subject?.paperUrl) {
    store.setting.subject.paperUrl =
      store.setting.fileServer + store.setting.subject?.paperUrl;
  }
  if (store.setting.subject?.paperUrl && store.isMultiMedia) {
    await getPaper(store);
  }
}

async function updateStatus() {
  const res = await getStatus();
  if (res.data.valid) Object.assign(store.status, res.data);
}
async function updateGroups() {
  const res = await getGroup();
  store.groups = res.data;
}

let preDrawing = false;
async function updateTask() {
  const res = await getTask();
  if (res.data.libraryId) {
    let rawTask = res.data;
    const newTask = addFileServerPrefixToTask(rawTask);
    store.tasks.push(newTask);
    if (!store.historyOpen) {
      // 在正评中，才能替换task
      if (store.currentTask?.studentId !== store.tasks[0].studentId)
        store.currentTask = store.tasks[0];
    }

    // 如果是评完后，再取到的任务，则此时要更新一下status
    if (store.status.totalCount - store.status.markedCount === 0) {
      await updateStatus();
    }

    // prefetch sliceUrls image
    if (store.tasks.length > 1) {
      // 如果不是当前任务，则先等3秒再去取任务，以免和其他请求争夺网络资源
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
    try {
      preDrawing = true;
      if (store.isScanImage) {
        await preDrawImage(newTask);
      }
    } finally {
      preDrawing = false;
    }
  } else {
    store.message = res.data.message;
  }
}

function nextTask() {
  // 正在预绘制中，则不要再取任务，以免拖慢当前任务的绘制
  if (!preDrawing) {
    if (store.tasks.length < (store.setting.prefetchCount ?? 3)) {
      // 回看打开时，停止取任务
      if (!store.historyOpen)
        return updateTask().catch((e) => console.log("定时获取任务出错", e));
    }
  }
}

// 5秒更新一次tasks
addInterval(nextTask, 5 * 1000);

// 不需要
// addInterval(() => {
//   updateStatus();
// }, 5 * 60 * 1000);

onMounted(async () => {
  await updateMarkTask();
  await updateSetting();
  await updateStatus();
  await updateGroups();
  await nextTask();
});

const __debounceUpdate = debounce(() => {
  updateUISetting(store.setting.mode, store.setting.uiSetting).catch((e) =>
    console.log("保存设置出错", e)
  );
}, 3000);
watch(
  () => [store.setting.uiSetting, store.setting.mode],
  () => {
    __debounceUpdate();
  },
  { deep: true }
);

const showRejectedReason = (task: Task) => {
  const rejectShowedTasksString = sessionStorage.getItem("reject-showed");

  let rejectShowedTasks: string[] = [];

  if (rejectShowedTasksString) {
    rejectShowedTasks = JSON.parse(rejectShowedTasksString);
  }

  if (
    rejectShowedTasks.includes(task.secretNumber) &&
    task.rejected &&
    task.rejectReason
  ) {
    const [reasonType, reasonDesc] = task.rejectReason.split(":");
    Modal.info({
      title: null,
      closable: false,
      maskClosable: false,
      centered: true,
      icon: null,
      okText: "知道了",
      wrapClassName: "custom-modal-info",
      zIndex: 9999,
      bodyStyle: {
        padding: "15px",
      },
      content: () =>
        h(
          "div",
          {
            style: {
              fontSize: "14px",
              color: "var(--app-main-text-color)",
            },
          },
          [
            h("div", { style: { marginBottom: "8px" } }, [
              h(
                "span",
                { style: { fontWeight: "bold", marginRight: "0.5em" } },
                "打回原因: "
              ),
              h("span", reasonType),
            ]),
            h("div", { style: { fontWeight: "bold" } }, "详情描述: "),
            h("div", { style: { padding: "4px 2px" } }, reasonDesc),
          ]
        ),
    });
  }
};

// 切换currentTask
watch(
  () => store.currentTask,
  () => {
    // 重置当前选择的quesiton和score
    store.currentQuestion = undefined;
    store.currentScore = undefined;
    void nextTick(() => {
      if (store.currentTask) {
        showRejectedReason(store.currentTask);
      }
    });
  }
);

const removeBrokenTask = () => {
  store.currentTask = undefined;

  if (store.historyOpen) {
    // store.currentTask = store.historyTasks[0];
    // 避免无限加载
    store.message = "加载失败，请重新选择。";
  } else {
    store.tasks.shift();
  }
};

const allZeroSubmit = async () => {
  const markResult = store.currentTask?.markResult;
  if (!markResult) return;

  const { markerScore, scoreList, trackList, specialTagList } = markResult;
  markResult.markerScore = 0;
  const ss = new Array(store.currentTaskEnsured.questionList.length);
  markResult.scoreList = ss.fill(0);
  markResult.trackList = [];

  try {
    await saveTaskToServer();
  } catch (error) {
    console.log("error restore");
  } finally {
    // console.log({ markerScore, scoreList, trackList });
    markResult.markerScore = markerScore;
    markResult.scoreList = scoreList;
    markResult.trackList = trackList;
    markResult.specialTagList = specialTagList;
  }
};

const unselectiveSubmit = async () => {
  const markResult = store.currentTask?.markResult;
  if (!markResult) return;

  try {
    const res = await doUnselectiveType();
    if (res?.data.success) {
      void message.success({ content: "未选做处理成功", duration: 3 });
      if (!store.historyOpen) {
        store.currentTask = undefined;
        store.tasks.shift();
        store.currentTask = store.tasks[0];
      }
      if (store.historyOpen) {
        EventBus.emit("should-reload-history");
      }
      await updateStatus();
    } else {
      void message.error({ content: res?.data.message || "错误", duration: 5 });
    }
  } catch (error) {
    console.log("未选做处理失败", error);
    void message.error({ content: "网络异常", duration: 5 });
    await new Promise((res) => setTimeout(res, 1500));
    window.location.reload();
  }
};

const saveTaskToServer = async () => {
  if (!store.currentTask) return;
  const markResult = store.currentTask.markResult;
  if (!markResult) return;

  const mkey = "save_task_key";

  type SubmitError = {
    question: Question;
    index: number;
    error: string;
  };

  const errors: SubmitError[] = [];
  markResult.scoreList.forEach((score, index) => {
    if (!store.currentTask) return;
    const question = store.currentTask.questionList[index]!;
    let error;
    if (!isNumber(score)) {
      error = `${question.mainNumber}-${question.subNumber} 没有赋分不能提交。`;
    } else if (isNumber(question.maxScore) && score > question.maxScore) {
      error = `${question.mainNumber}-${question.subNumber} 赋分大于最高分不能提交。`;
    } else if (isNumber(question.minScore) && score < question.minScore) {
      error = `${question.mainNumber}-${question.subNumber} 赋分小于最低分不能提交。`;
    }
    if (error) {
      errors.push({ question, index, error });
    }
  });
  if (errors.length !== 0) {
    console.log(errors);
    const msg = errors.map((v) => h("div", `${v.error}`));
    void message.warning({
      content: h("span", ["校验失败", ...msg]),
      duration: 10,
      key: mkey,
    });
    return;
  }

  if (
    markResult.scoreList.length !== store.currentTask.questionList.length ||
    !markResult.scoreList.every((s) => isNumber(s))
  ) {
    console.error({ content: "markResult格式不正确，缺少分数", key: mkey });
    return;
  }

  if (!store.isTrackMode) {
    markResult.trackList = [];
  } else {
    const trackScores =
      markResult.trackList
        .map((t) => Math.round((t.score || 0) * 100))
        .reduce((acc, s) => acc + s, 0) / 100;
    if (trackScores !== markResult.markerScore) {
      void message.error({
        content: "轨迹分与总分不一致，请检查。",
        duration: 3,
        key: mkey,
      });
      return;
    }
  }
  if (store.setting.forceSpecialTag) {
    if (
      markResult.trackList.length === 0 &&
      markResult.specialTagList.length === 0
    ) {
      void message.error({
        content: "强制标记已开启，请至少使用一个标记。",
        duration: 5,
        key: mkey,
      });
      return;
    }
  }
  console.log("save task to server");
  void message.loading({ content: "保存评卷任务...", key: mkey });
  const res = await saveTask();
  if (!res) return;
  // 故意不在此处同步等待，因为不必等待
  updateStatus().catch((e) => console.log("保存任务后获取status出错", e));
  if (res.data.success && store.currentTask) {
    void message.success({ content: "保存成功", key: mkey, duration: 2 });
    if (!store.historyOpen) {
      store.currentTask = undefined;
      store.tasks.shift();
      store.currentTask = store.tasks[0];
    } else {
      EventBus.emit("should-reload-history");
    }
  } else if (res.data.message) {
    console.log(res.data.message);
    void message.error({ content: res.data.message, key: mkey, duration: 10 });
  } else if (!store.currentTask) {
    void message.warn({ content: "暂无新任务", key: mkey, duration: 10 });
  }
  // 获取下一个任务
  void nextTask();
};
</script>

<style>
.custom-modal-info .ant-modal-content {
  border-radius: 4px;
}
</style>

<style scoped>
.my-container {
  width: 100%;
  overflow: clip;
}

.status-spin {
  position: absolute;
  top: 0;
  left: 0;
  min-width: max(var(--app-min-width), 100%);
  height: 100vh;
  z-index: 6000;
  background-color: rgba(200, 200, 200, 0.7);
}
</style>
