<template>
  <div class="mark-body-container tw-flex-auto tw-p-2" ref="dragContainer">
    <a-spin
      :spinning="rendering"
      size="large"
      tip="Loading..."
      style="margin-top: 50px"
    >
      <div v-if="!store.currentTask" class="tw-text-center">
        {{ store.message }}
      </div>
      <div v-else :style="{ width: answerPaperScale }">
        <div
          v-for="(item, index) in sliceImagesWithTrackList"
          :key="index"
          class="single-image-container"
        >
          <img :src="item.url" draggable="false" />
          <MarkDrawTrack
            :track-list="item.trackList"
            :special-tag-list="item.tagList"
            :original-image="item.originalImage"
          />
          <hr class="image-seperator" />
        </div>
      </div>
    </a-spin>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, reactive, ref, watchEffect } from "vue";
import { store } from "./store";
import filters from "@/filters";
import MarkDrawTrack from "./MarkDrawTrack.vue";
import { SpecialTag, Track } from "@/types";
import { useTimers } from "@/setups/useTimers";
import { loadImage } from "@/utils/utils";
import { dragImage } from "@/features/mark/use/draggable";

interface SliceImage {
  url: string;
  indexInSliceUrls: number;
  trackList: Array<Track>;
  tagList: Array<SpecialTag>;
  originalImage: HTMLImageElement;
}
// should not render twice at the same time
let __lock = false;
let __currentStudentId = -1; // save __currentStudentIdof lock
export default defineComponent({
  name: "MarkBody",
  components: { MarkDrawTrack },
  emits: ["error"],
  setup(props, { emit }) {
    const { dragContainer } = dragImage();

    const { addTimeout } = useTimers();

    let rendering = ref(false);
    let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);

    async function processImage() {
      if (!store.currentTask) return;

      const images = [];
      for (const url of store.currentTask.sliceUrls) {
        const image = await loadImage(
          filters.toCompleteUrlWithFileServer(store.setting.fileServer, url)
        );
        images.push(image);
      }

      for (const url of store.currentTask.sliceUrls) {
        const completeUrl = filters.toCompleteUrlWithFileServer(
          store.setting.fileServer,
          url
        );

        const indexInSliceUrls = store.currentTask.sliceUrls.indexOf(url) + 1;
        const image = images[indexInSliceUrls - 1];

        const trackLists = store.currentTask.questionList
          .map((q) => q.trackList)
          .reduce((acc, t) => {
            acc = acc.concat(t);
            return acc;
          }, [] as Array<Track>);
        const thisImageTrackList = trackLists.filter(
          (t) => t.offsetIndex === indexInSliceUrls
        );
        const thisImageTagList = store.currentTask.specialTagList?.filter(
          (t) => t.offsetIndex === indexInSliceUrls
        );

        sliceImagesWithTrackList.push({
          url: completeUrl,
          indexInSliceUrls,
          trackList: thisImageTrackList,
          tagList: thisImageTagList,
          originalImage: image,
        });
      }
    }
    const renderPaperAndMark = async () => {
      if (__lock) {
        if (store.currentTask?.studentId === __currentStudentId) {
          console.log("重复渲染，返回");
          return;
        }
        console.log("上个任务还未渲染完毕，稍等一秒再尝试渲染");
        await new Promise((res) => setTimeout(res, 1000));
        await renderPaperAndMark();
        return;
      }
      __lock = true;
      __currentStudentId = store.currentTask?.studentId ?? -1;
      sliceImagesWithTrackList.splice(0);

      if (!store.currentTask) {
        __lock = false;
        return;
      }

      try {
        rendering.value = true;
        await processImage();
      } catch (error) {
        sliceImagesWithTrackList.splice(0);
        console.log("render error ", error);
        // 图片加载出错，自动加载下一个任务
        emit("error");
      } finally {
        __lock = false;
        rendering.value = false;
      }
    };

    watchEffect(renderPaperAndMark);

    const answerPaperScale = computed(() => {
      // 放大、缩小不影响页面之前的滚动条定位
      let percentWidth = 0;
      let percentTop = 0;
      const container = document.querySelector(
        ".mark-body-container"
      ) as HTMLDivElement;
      if (container) {
        const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
        percentWidth = scrollLeft / scrollWidth;
        percentTop = scrollTop / scrollHeight;
      }

      addTimeout(() => {
        if (container) {
          const { scrollWidth, scrollHeight } = container;
          container.scrollTo({
            left: scrollWidth * percentWidth,
            top: scrollHeight * percentTop,
          });
        }
      }, 10);
      const scale = store.setting.uiSetting["answer.paper.scale"];
      return scale * 100 + "%";
    });

    return {
      dragContainer,
      store,
      rendering,
      sliceImagesWithTrackList,
      answerPaperScale,
    };
  },
});
</script>

<style scoped>
.mark-body-container {
  height: calc(100vh - 41px);
  overflow: scroll;
  background-size: 8px 8px;
  background-image: linear-gradient(to right, #e7e7e7 4px, transparent 4px),
    linear-gradient(to bottom, transparent 4px, #e7e7e7 4px);

  cursor: grab;
  user-select: none;
}
.grabbing {
  cursor: grabbing;
}
.mark-body-container img {
  width: 100%;
}
.single-image-container {
  position: relative;
}
.image-seperator {
  border: 2px solid rgba(120, 120, 120, 0.1);
}
</style>
