<template>
  <div class="pano-layout" v-loading="loading">
    <canvas ref="panoDomRef"></canvas>
    <div class="btns">
      <el-button
        size="large"
        type="primary"
        style="margin-right: 20px; width: 100px"
        @click="photo"
      >
        屏幕拍照
      </el-button>
      <el-button
        size="large"
        style="margin-right: 20px; width: 100px"
        @click="copyGis"
        v-if="point && !noValidPoint(point)"
      >
        复制经纬度
      </el-button>
      <el-button
        size="large"
        type="primary"
        style="width: 100px"
        @click="update = true"
        v-if="router.currentRoute.value.name === 'pano'"
      >
        测点说明
      </el-button>
    </div>
  </div>
  <SingleInput
    v-if="point"
    :visible="update"
    @update:visible="update = false"
    :value="point"
    :update-value="(npoint) => updateScenePointName(npoint)"
  />
</template>

<script setup lang="ts">
import SingleInput from "@/components/point-input.vue";
import { router, setDocTitle } from "@/router";
import { mergeFuns, round } from "@/util";
import { computed, onMounted, onUnmounted, ref, watchEffect } from "vue";
import { init } from "./env";
import {
  updateScenePointName,
  getPointPano,
  ScenePoint,
  scenePoints,
} from "@/store/scene";
import { copyText, toDegrees, getTextBound } from "@/util";
import { ElMessage } from "element-plus";
import saveAs from "@/util/file-serve";
import { DeviceType } from "@/store/device";
import { initRelics, relics } from "@/store/relics";
import { noValidPoint } from "../map/install";

type Params = { pid?: string; relicsId?: string } | null;
const params = computed(() => router.currentRoute.value.params as Params);
const panoDomRef = ref<HTMLCanvasElement>();
const destroyFns: (() => void)[] = [];
const point = ref<ScenePoint>();
watchEffect(() => {
  if (params.value?.pid) {
    const pid = Number(params.value!.pid);
    point.value = scenePoints.value.find((scene) => scene.id === pid);

    if (!point.value) {
      initRelics(Number(params.value.relicsId)).then(() => {
        point.value = scenePoints.value.find((scene) => scene.id === pid);
        if (!point.value) {
          router.replace({ name: "relics" });
        }
      });
    }
  }
});

const panoUrls = computed(() => {
  return (
    point.value && getPointPano(point.value, point.value.cameraType === DeviceType.CLUNT)
  );
});
const update = ref(false);
const loading = ref(false);

const getGis = () => {
  const pos = point.value!.pos as number[];
  return `经度: ${toDegrees(pos[0])}\n纬度: ${toDegrees(pos[1])}\n高程: ${round(
    pos[2],
    4
  )}`;
};

const copyGis = async () => {
  await copyText(getGis());
  ElMessage.success("经纬度高程复制成功");
};

const canvas = document.createElement("canvas");
// 水印添加函数
const addWatermark = (imgURL: string, ration: number) => {
  const ctx = canvas.getContext("2d");
  const image = new Image();
  image.src = imgURL;

  return new Promise<string>((resolve, reject) => {
    image.onload = () => {
      canvas.width = image.width;
      canvas.height = image.height;
      ctx.drawImage(image, 0, 0, image.width, image.height);

      const font = `${ration * 20}px Arial`;
      const pos = point.value!.pos as number[];
      const lines = `经度: ${toDegrees(pos[0])}\n纬度: ${toDegrees(pos[1])}`.split("\n");
      const lineTopPadding = 5 * ration;
      const lineBounds = lines.map((line) =>
        getTextBound(line, font, [lineTopPadding, 0])
      );
      const bound = lineBounds.reduce(
        (t, { width, height }) => {
          t.width = Math.max(t.width, width);
          t.height += height;
          return t;
        },
        { width: 0, height: 0 }
      );
      const padding = 20 * ration;
      const margin = 80 * ration;

      const position = [
        image.width - margin - bound.width,
        image.height - margin - bound.height,
      ];

      ctx.rect(
        position[0] - padding,
        position[1] - padding,
        bound.width + 2 * padding,
        bound.height + 2 * padding
      );
      ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
      ctx.fill();

      ctx.font = font;
      ctx.textBaseline = "top";
      ctx.fillStyle = "#fff";
      let itemTop = 0;
      lines.forEach((line, ndx) => {
        ctx.fillText(line, position[0], position[1] + itemTop + lineTopPadding);
        itemTop += lineBounds[ndx].height;
      });
      resolve(canvas.toDataURL("image/jpg", 1));
    };
    image.onerror = reject;
  });
};

const photo = async () => {
  loading.value = true;
  await new Promise((resolve) => setTimeout(resolve, 300));
  const ration = 3;
  setSize(ration, 1920, 1080);
  let dataURL = panoDomRef.value.toDataURL("image/jpg", 1);
  if (!noValidPoint(point.value)) {
    dataURL = await addWatermark(dataURL, ration);
  }

  await saveAs(dataURL, `${relics.value?.name}.jpg`);
  ElMessage.success("图片导出成功");
  setSize(devicePixelRatio);
  loading.value = false;
};

let pano: ReturnType<typeof init>;
const setSize = (ration: number, w?: number, h?: number) => {
  const canvas = panoDomRef.value!;
  canvas.width = (w || canvas.offsetWidth) * ration;
  canvas.height = (h || canvas.offsetHeight) * ration;
  pano.setSize([canvas.width, canvas.height]);
};

onMounted(() => {
  if (!panoDomRef.value) throw "没有canvas DOM";
  pano = init(panoDomRef.value);
  const resizeHandler = () => {
    setSize(devicePixelRatio);
  };
  resizeHandler();

  window.addEventListener("resize", resizeHandler);
  destroyFns.push(
    watchEffect(() => {
      if (panoUrls.value) {
        loading.value = true;
        pano.changeUrls(panoUrls.value).then(() => (loading.value = false));
      }
    }),
    pano.destory,
    () => {
      window.removeEventListener("resize", resizeHandler);
    }
  );
});

onUnmounted(() => mergeFuns(...destroyFns)());
watchEffect(() => {
  if (router.currentRoute.value.name.toString().includes("pano") && point.value) {
    setDocTitle(point.value.index.toString() || relics.value.name);
  }
});
</script>

<style scoped lang="scss">
.pano-layout,
canvas {
  width: 100%;
  height: 100%;
}

.pano-layout {
  position: relative;
  .btns {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: 40px;
    z-index: 1;
  }
}
</style>
