<template>
  <div
    v-if="show && posStyle"
    class="hot-item pc"
    :style="posStyle"
    @mouseenter="isHover = true"
    @mouseleave="isHover = false"
  >
    <div @click.stop>
      <UIBubble
        class="hot-bubble pc"
        :show="showContent"
        type="left"
        level="center"
        @click.stop
        @pointerdown.stop
        @pointerup.stop
      >
        <h2>
          {{ tagging.title }}
          <ui-audio
            v-if="tagging.audio"
            class="audio"
            :src="getResources(getFileUrl(tagging.audio))"
            ref="audio"
          />
        </h2>
        <div class="content">
          <template v-if="defStyleType.id !== taggingStyle?.typeId && tagging.part">
            <p><span>遗留部位：</span>{{ tagging.part }}</p>
          </template>
          <div class="p" v-if="tagging.desc">
            <span v-if="defStyleType.id !== taggingStyle?.typeId"> 特征描述： </span>
            <div v-html="tagging.desc"></div>
          </div>
          <template v-if="defStyleType.id !== taggingStyle?.typeId">
            <p v-if="tagging.method"><span>提取方法：</span>{{ tagging.method }}</p>
            <p v-if="tagging.tqTime"><span>提取时间：</span>{{ tagging.tqTime }}</p>
            <p v-if="tagging.principal"><span>提取人：</span>{{ tagging.principal }}</p>
            <p v-if="tagging.tqStatus"><span>委托状态：</span>{{ tagging.tqStatus }}</p>
          </template>
        </div>
        <Images
          class="images"
          :tagging="tagging"
          :in-full="true"
          @pull="(index) => (pullIndex = index)"
        />
        <div class="edit-hot" v-if="showDelete">
          <span @click="$emit('delete')" class="fun-ctrl">
            <ui-icon type="del" />
            {{ $t("sys.del") }}
          </span>
        </div>
      </UIBubble>

      <Preview
        @close="pullIndex = -1"
        :current="pullIndex"
        :items="queryItems"
        v-if="!!~pullIndex"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, markRaw, onUnmounted, ref, watch, watchEffect } from "vue";
import UIBubble from "bill/components/bubble/index.vue";
import Images from "@/views/tagging/hot/images.vue";
import Preview from "../static-preview/index.vue";
import { getTaggingStyle } from "@/store";
import { getFileUrl } from "@/utils";
import { sdk, TaggingPositionNode } from "@/sdk";
import { custom, getResource, getResources } from "@/env";

import type { Tagging, TaggingPosition } from "@/store";
import { useCameraChange, usePixel } from "@/hook/use-pixel";
import { inRevise } from "bill/utils";
import { defStyleType } from "@/api";

export type SignProps = { tagging: Tagging; scenePos: TaggingPosition; show?: boolean };

const props = defineProps<SignProps>();
const emit = defineEmits<{
  (e: "delete"): void;
  (e: "changeLineHeight", val: number): void;
  (
    e: "changePosition",
    val: { position: SceneLocalPos; modelId: string; normal: SceneLocalPos; pose?: any }
  ): void;
}>();

const audio = ref();
watchEffect(() => {
  if (props.show && audio.value) {
    audio.value.play();
  }
});
const [posStyle, pos, pause, recovery] = usePixel(() => undefined);

const queryItems = computed(() =>
  props.tagging.images.map((image) => ({
    url: getResource(getFileUrl(image)),
  }))
);
console.log(props.tagging.styleId);
const taggingStyle = computed(() => getTaggingStyle(props.tagging.styleId));
const tag = markRaw(
  sdk.createTagging({
    ...props.scenePos,
    title: props.tagging.title,
    position: props.scenePos.localPos,
    canMove: false,
    image: getFileUrl(taggingStyle.value!.icon),
  })
) as TaggingPositionNode;
const showDelete = ref(false);
tag.showDelete = (show) => {
  showDelete.value = show;
};

tag.changeCanMove(false);

const changePos = () => {
  pos.value = { localPos: tag.getImageCenter(), modelId: props.scenePos.modelId };
};

watch(taggingStyle, (icon) => icon && tag.changeImage(getFileUrl(icon.icon)));
watchEffect(() => tag.changeMat(props.scenePos.mat));
watchEffect(() => tag.changeFontSize(props.scenePos.fontSize));
watchEffect(() => tag.changeTitle(props.tagging.title));
watchEffect(() => tag.visibilityTitle(props.tagging.show3dTitle));
watchEffect(() => {
  tag.changeType(props.scenePos.type);
  changePos();
});
const getPosition = () => ({
  position: props.scenePos.localPos,
  normal: props.scenePos.normal,
  modelId: props.scenePos.modelId,
});
let currentPosition = getPosition();
let changeTimeout: any;
tag.bus.on("changePosition", (data) => {
  clearTimeout(changeTimeout);
  emit(
    "changePosition",
    (currentPosition = {
      position: { ...data.pos },
      normal: { ...data.normal },
      modelId: data.modelId,
    })
  );
  changePos();
});
tag.bus.on("scaleChanged", () => changePos());

tag.bus.on("changePosition", (data) => {
  clearTimeout(changeTimeout);
  currentPosition = {
    position: { ...data.pos },
    normal: { ...data.normal },
    modelId: data.modelId,
  };
  emit("changePosition", {
    ...currentPosition,
    pose: sdk.getPose({ modelId: data.modelId, isFlyToTag: true }),
  });
  changePos();
});
tag.bus.on("changeLineHeight", (lineHeight) => {
  emit("changeLineHeight", lineHeight);
});

watch(getPosition, (p) => {
  changeTimeout = setTimeout(() => {
    if (inRevise(p, currentPosition)) {
      tag.changePosition(p);
      currentPosition = p;
    }
  }, 16);
});

watch(
  () => props.scenePos.lineHeight,
  () => {
    changeTimeout = setTimeout(() => {
      tag.changeLineHeight(props.scenePos.lineHeight);
      changePos();
    }, 16);
  },
  { immediate: true }
);

const [toCameraDistance] = useCameraChange(() => {
  return tag.getCameraDisSquared && tag.getCameraDisSquared();
});
const show = computed(
  () =>
    props.scenePos.globalVisibility ||
    toCameraDistance.value <= Math.pow(props.scenePos.visibilityRange, 2)
);
watchEffect(() => tag.visibility(show.value));

const isHover = ref(false);
tag.bus.on("enter", () => {
  isHover.value = true;
});
tag.bus.on("leave", () => {
  isHover.value = false;
});
tag.bus.on("click", () => iconClickHandler());

const sHover = ref(isHover.value);
let timeout: any;
watchEffect(() => {
  clearTimeout(timeout);
  if (isHover.value) {
    sHover.value = true;
  } else {
    timeout = setTimeout(() => {
      sHover.value = false;
    }, 100);
  }
});
const pullIndex = ref(-1);
const showContent = computed(() => {
  return (
    !~pullIndex.value && (sHover.value || custom.showTaggingPositions.has(props.scenePos))
  );
});
watchEffect(() => {
  if (showContent.value) {
    recovery();
  } else {
    pause();
  }
});

const iconClickHandler = () => {
  if (custom.showTaggingPositions.has(props.scenePos)) {
    custom.showTaggingPositions.delete(props.scenePos);
  } else {
    custom.showTaggingPositions.add(props.scenePos);
  }
};

console.log("标签 创建", props.tagging.id);
onUnmounted(() => {
  tag.destroy();
  clearTimeout(timeout);
  clearTimeout(changeTimeout);
  console.error("标签 销毁", props.tagging.id);
});

defineExpose(tag);
</script>

<style lang="scss" scoped>
.hot-item {
  pointer-events: all;
  position: absolute;
  transform: translate(-50%, -100%);
  cursor: pointer;

  .tag-img {
    width: 32px;
    height: 32px;
  }

  .hot-bubble {
    cursor: initial;

    &.pc {
      width: 400px;
    }

    &:not(.pc) {
      width: 80vw;
      --bottom-left: 40vw;
    }

    h2 {
      font-size: 20px;
      margin-bottom: 10px;
      color: #ffffff;
      position: relative;
      display: flex;
      justify-content: space-between;
    }

    .content {
      font-size: 14px;
      font-family: MicrosoftYaHei;
      color: #999999;
      line-height: 1.35em;
      margin-bottom: 20px;
      word-break: break-all;

      .p,
      p {
        margin-bottom: 10px;
        display: flex;
        span {
          flex: 0 0 auto;
        }
      }
    }
  }

  &.active,
  &:hover {
    z-index: 3;
  }
}

.edit-hot {
  margin-top: 20px;
  text-align: right;

  span {
    font-size: 14px;
    color: rgba(255, 255, 255, 0.6);
    cursor: pointer;
  }
}

.images {
  height: 250px;
}
</style>

<style>
.tag-tip {
  z-index: 8 !important;
}

.tag-tip p {
  padding: 6px 10px !important;
  margin: 5px 0 !important;
}
</style>
