<template>
  <div class="pano-layout" v-loading="loading" :element-loading-text="loadingStr">
    <div class="canvas-layout">
      <canvas ref="panoDomRef"></canvas>
    </div>
    <div class="btns">
      <el-button
        size="large"
        type="primary"
        style="margin-right: 20px; width: 100px"
        @click="photo"
      >
        屏幕拍照
      </el-button>
      <!-- <el-input-number
        style="margin-right: 20px"
        v-model="tempRadion"
        :precision="2"
        :step="0.01"
        :min="1"
        :max="3"
      /> -->
      <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 { glMatrix } from "gl-matrix";
import {
  computed,
  onActivated,
  onMounted,
  onUnmounted,
  ref,
  shallowRef,
  watch,
  watchEffect,
} from "vue";
import { init } from "./three-env";
// import { init } from "./env";
import {
  updateScenePointName,
  getPointPano,
  ScenePoint,
  scenePoints,
  SceneType,
} from "@/store/scene";
import { copyText, toDegrees } 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";
import { addWatermark } from "@/util/image";
import { inRevise } from "@/lib/board/4dmap";
import { Texture } from "three";

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>();
const tempRadion = ref(3.0);

watch(
  params,
  (params) => {
    if (!params?.pid) return;
    const pid = Number(params!.pid);
    point.value = scenePoints.value.find((scene) => scene.id === pid);
    try {
      pano?.reset();
    } catch {}
    if (!point.value) {
      initRelics(Number(params.relicsId)).then(() => {
        point.value = scenePoints.value.find((scene) => scene.id === pid);
        if (!point.value) {
          router.replace({ name: "relics" });
        }
      });
    }
  },
  { immediate: true }
);

const panoUrls = ref<string | string[]>();
watchEffect(() => {
  if (point.value) {
    panoUrls.value = getPointPano(
      point.value,
      [SceneType.CLUNT, SceneType.MESH].includes(point.value.sceneType)
    );
  }
});

const update = ref(false);
const loading = ref(false);
const loadingStr = ref("");

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("经纬度高程复制成功");
};

let prevBigImages: string | string[];
let prevBigTexs: Texture[];
const photo = async () => {
  loading.value = true;
  const bigImages = getPointPano(
    point.value,
    [SceneType.CLUNT, SceneType.MESH].includes(point.value.sceneType),
    false
  );
  if (
    inRevise(panoUrls.value, bigImages) &&
    (!prevBigTexs || inRevise(prevBigImages, bigImages))
  ) {
    if (prevBigTexs) {
      prevBigTexs.forEach((tex) => tex.dispose());
    }
    prevBigTexs = await pano.getTexs(bigImages);
    prevBigImages = bigImages;
    pano.changeEnv(prevBigTexs);
    pano.redraw();
  }

  loadingStr.value = "原图提取中";
  await new Promise((resolve) => setTimeout(resolve, 300));
  const ration = tempRadion.value;
  setSize(ration, 1920, 1080);

  let dataURL: Blob | string = panoDomRef.value.toDataURL("image/jpeg", 1);
  if (!noValidPoint(point.value)) {
    dataURL = await addWatermark(dataURL, point.value!.pos, ration);
  }

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

  prevBigTexs.forEach((tex) => tex.dispose());
  prevBigTexs = null;
  prevBigImages = null;
};

let pano: ReturnType<typeof init>;
const setSize = (ration: number, w?: number, h?: number) => {
  const canvas = panoDomRef.value!.parentElement;

  w = (w || canvas.offsetWidth) * ration;
  h = (h || canvas.offsetHeight) * ration;
  pano.setSize([w, h]);
  pano.redraw();
};

const thumbnailTexs = shallowRef<Texture[]>([]);
onMounted(() => {
  if (!panoDomRef.value) throw "没有canvas DOM";
  pano = init(panoDomRef.value);
  const resizeHandler = () => {
    setSize(1);
  };
  resizeHandler();

  window.addEventListener("resize", resizeHandler);
  const s1 = watch(
    panoUrls,
    (n, o) => {
      if (inRevise(n, o) && n) {
        loading.value = true;
        //     getPointPano(
        //   point.value,
        //   [SceneType.CLUNT, SceneType.MESH].includes(point.value.sceneType)
        // )
        pano.getTexs(n).then(
          (texs) => {
            loading.value = false;
            thumbnailTexs.value.forEach((t) => t.dispose());
            thumbnailTexs.value = texs;
          },
          (err) => {
            loading.value = false;
            panoUrls.value = getPointPano(
              point.value,
              [SceneType.CLUNT, SceneType.MESH].includes(point.value.sceneType),
              false
            );
          }
        );
      }
    },
    { flush: "sync", immediate: true }
  );
  const s2 = watchEffect(() => {
    if (point.value) {
      // console.log(point.value.sceneType);
      // SceneType.VR
      const yaw =
        point.value.sceneType === SceneType.MESH ||
        point.value.sceneType === SceneType.CLUNT
          ? 90
          : -90;
      pano.setYaw(glMatrix.toRadian(yaw));
    }
  });
  const s3 = watchEffect(() => {
    if (thumbnailTexs.value.length) {
      pano.changeEnv(thumbnailTexs.value);
    }
  });

  destroyFns.push(s1, s2, s3, pano.destory, () => {
    thumbnailTexs.value.forEach((t) => t.dispose());
    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-layout,
canvas {
  width: 100%;
  height: 100%;
}

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