<template>
  <div class="title title_grey cl">
    <h2>图片下载中 …</h2>
  </div>
  <div class="progress-box">
    <h3>正在下载图片，请耐心等候 ~</h3>
    <div class="progress">
      <a-progress :percent="Math.round((finishedCount / totalCount) * 100)" />
    </div>
    <p>
      已下载图片：<b>{{ finishedCount }}</b> / 错误图片：<b>{{ errorCount }}</b>
      / 全部图片：<b>{{ totalCount }}</b>
    </p>
  </div>
</template>

<script setup lang="ts">
import { store } from "@/store";
import { onMounted, onUnmounted, ref } from "vue";
import { Modal } from "ant-design-vue";
import { useRouter } from "vue-router";
const router = useRouter();
import { getStudents, countStudents, getPackages } from "@/api/api";
import { httpApp } from "@/plugins/axiosApp";
import mustache from "mustache";

async function getImageDim(
  blob: Blob
): Promise<[width: number, height: number]> {
  return new Promise((res) => {
    const img = new Image();
    img.src = URL.createObjectURL(blob);
    img.onload = () => {
      URL.revokeObjectURL(img.src);
      // console.log(img.width);
      res([img.width, img.height]);
    };
  });
}

// cache images
async function cacheImages(urls: string) {
  let allPromiseCount = 0;
  let settledPromiseCount = 0;
  const MAX_CONCURRENT = 6;

  async function sleep() {
    if (allPromiseCount - settledPromiseCount >= MAX_CONCURRENT) {
      console.log("sleep because cache images thread is full");
      await new Promise((res) => setTimeout(res, 300));
      await sleep();
    }
  }
  for (const url of urls) {
    allPromiseCount++;
    await sleep();
    // console.log(url);
    httpApp
      .get(url, {
        responseType: "blob",
        headers: {
          // 怀疑 electron 有问题，这里没生效
          "Cache-Control": "no-cache",
        },
      })
      .then(() => console.debug("downloaded ", url))
      .catch((e) => {
        console.log(e, "cache error");
      })
      .finally(() => {
        settledPromiseCount++;
      });
  }
}

const totalCount = ref(0);
let finishedCount = ref(0);
let errorCount = ref(0);
let students = [];

const config = store.pageInputs["/image-download"];
onMounted(async () => {
  const storePassedToNodeJs = JSON.parse(JSON.stringify(store));
  try {
    if (config.type === "1") {
      console.log("download start ", Date.now());
      const res = await countStudents(store.env.examId, {
        upload: true,
        withSheetUrl: true,
        withScoreDetail: config.watermark,
        withGroupScoreTrack: config.watermark && config.trackMode,
        examNumberIn: config.examNumber ?? "",
        subjectCodeIn: config.subjectCode ?? "",
      });
      totalCount.value = res.data;
      let totalImageDownloadTime = 0;

      for (
        let pageNumber = 0;
        pageNumber * 10 < totalCount.value;
        pageNumber++
      ) {
        const resStudents = await getStudents(
          store.env.examId,
          pageNumber + 1,
          10,
          {
            upload: true,
            withSheetUrl: true,
            withScoreDetail: config.watermark,
            withGroupScoreTrack: config.watermark && config.trackMode === "1",
            examNumberIn: config.examNumber ?? "",
            subjectCodeIn: config.subjectCode ?? "",
          }
        );
        students = resStudents.data;

        const urls = students.reduce(
          (accumulator, stu) => accumulator.concat(stu.sheetUrls),
          []
        );
        cacheImages(urls);

        for (const student of students) {
          for (const sheetUrl of student.sheetUrls) {
            if (stopSignal) return;
            try {
              const index = student.sheetUrls.indexOf(sheetUrl);
              student.index = index + 1;
              student.examId = store.env.examId;
              // const filePath = window.electron.join(
              //   config.dir,
              //   mustache.render(config.template, student)
              // );
              const filePath = [
                config.dir,
                mustache.render(config.template, student),
              ];
              if (config.append && window.electron.existsImage(filePath)) {
                console.log(filePath + " already exists");
                // 执行到这里时，可能图片已经cache了
                urls.splice(urls.indexOf(sheetUrl), 1);
                // console.log(urls);
                continue;
              }

              console.debug("start ", sheetUrl);
              const imageDownloadStartTime = Date.now();
              const imageRes = await httpApp.get(sheetUrl, {
                responseType: "blob",
                headers: {
                  "Cache-Control": "no-cache",
                },
              });
              totalImageDownloadTime += Date.now() - imageDownloadStartTime;

              const [width, height] = await getImageDim(imageRes.data);
              const arrayBuffer = await imageRes.data.arrayBuffer();

              // console.log(imageRes.data);
              // console.log(await imageRes.data.arrayBuffer());
              // console.log(new Uint8Array(await imageRes.data.arrayBuffer()));

              await window.electron.addWatermark(
                storePassedToNodeJs,
                arrayBuffer,
                width,
                height,
                filePath,
                student,
                index + 1,
                config.trackMode,
                config.x,
                config.y
              );
            } catch (error) {
              errorCount.value += 1;
              if (config.failover) {
                throw error;
              } else {
                console.log(student, error);
                continue;
              }
            }
          }
          // 下载完一个学生
          finishedCount.value += 1;
        }
      }
      console.log(
        "all end at ",
        Date.now(),
        " totalImageDownloadTime: ",
        totalImageDownloadTime
      );
    } else if (config.type === "2") {
      await processPackage();
    }

    const modal = Modal.success({});
    modal.update({
      title: "图片下载完成",
      content: "完成",
      onOk: () => router.back(),
    });
  } catch (error) {
    const modal = Modal.error({});
    console.log(error);
    modal.update({
      title: "图片下载出错",
      content: error.message || error,
      onOk: () => router.back(),
    });
  }
});

async function processPackage() {
  const res = await getPackages(store.env.examId, true, true);
  const array = res.data;
  totalCount.value = array.length;
  const urls = array.reduce((accumulator, p) => accumulator.concat(p.urls), []);
  cacheImages(urls);

  for (let i = 0; i < array.length; i++) {
    const p = array[i];
    p.examId = store.env.examId;
    for (let i = 0; i < p.urls.length; i++) {
      if (stopSignal) return;
      try {
        const index = i + 1;
        p.index = index;
        const filePath = [config.dir, mustache.render(config.template, p)];
        if (config.append && window.electron.existsImage(filePath)) {
          console.log(filePath + " already exists");
          urls.splice(urls.indexOf(p.urls[i]), 1);
          continue;
        }

        const imageRes = await httpApp.get(p.urls[i], {
          responseType: "blob",
        });

        await window.electron.saveImage(
          JSON.parse(JSON.stringify(store)),
          await imageRes.data.arrayBuffer(),
          filePath
        );
      } catch (error) {
        errorCount.value += 1;
        if (config.failover) {
          throw error;
        } else {
          console.log(p, error);
          continue;
        }
      }
    }
    finishedCount.value += 1;
  }
}

let stopSignal = false;
onUnmounted(() => (stopSignal = true));
</script>
