<template>
  <div
    class="draw-layout"
    id="draw-renderer"
    ref="layout"
    :style="{ cursor: cursorStyle }"
  >
    <template v-if="layout">
      <v-stage ref="stage" :config="size">
        <v-layer :config="viewerConfig" id="formal">
          <v-rect :config="config" ref="shape" />
          <slot />
        </v-layer>
      </v-stage>
    </template>
  </div>
</template>

<script lang="ts" setup>
import { computed, getCurrentInstance, onUnmounted, ref, watch, watchEffect } from "vue";
import {
  mergeFuns,
  rendererMap,
  useCursor,
  useGlobalResize,
  useGlobalVar,
  useStage,
  useViewer,
  useViewerInvertTransform,
  useViewerInvertTransformConfig,
  useViewerTransform,
  useViewerTransformConfig,
} from "./hook";
import { install } from "./install-lib";
import { Pos } from "./dec";

const props = defineProps<{ scale: { value: number; center: Pos } }>();
const emit = defineEmits<{ (e: "update:scaleValue", v: number): void }>();

const instance = getCurrentInstance();
install(instance!.appContext.app);

rendererMap.set(instance, { unmounteds: [] });
onUnmounted(() => {
  mergeFuns(rendererMap.get(instance)!.unmounteds)();
});

const stage = useStage();
const { size } = useGlobalResize();
const layout = ref();
const viewerConfig = useViewerTransformConfig();

const cursor = useCursor();
const cursorStyle = computed(() => {
  if (cursor.value.includes(".")) {
    return `url(${cursor.value}), auto`;
  } else {
    return cursor.value;
  }
});

const viewer = useViewer();
watch(
  () => props.scale,
  (scale) => {
    if (size.value) {
      viewer.viewer.scalePixel(scale.center, {
        x: scale.value / viewerConfig.value.scaleX,
        y: 1,
      });
    }
  },
  { deep: true }
);
watchEffect(
  () => {
    if (Math.abs(props.scale.value - viewerConfig.value.scaleX) > 0.001) {
      emit("update:scaleValue", viewerConfig.value.scaleX);
    }
  },
  { flush: "post" }
);

const invConfig = useViewerInvertTransformConfig();
const viewMat = useViewerTransform();
const viewInvertMat = useViewerInvertTransform();
const config = computed(
  () =>
    size.value && {
      ...invConfig.value,
      ...size.value,
    }
);
const { updateSize } = useGlobalResize();
const { misPixel } = useGlobalVar();
defineExpose({
  updateSize,
  getTimeScreen(time: number) {
    return viewMat.value.point({ x: time * misPixel, y: 0 }).x;
  },
});
</script>

<style scoped lang="scss">
.draw-layout {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;

  .draw-content {
    position: relative;
    width: 100%;
    height: 100%;
  }
}

.mount-mask {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 999;
}
</style>
