<script setup lang="ts">
interface Props {
  opacityWhenVisible?: number;
}

const SCREEN_MARGIN = 10;

import { onBeforeMount, onBeforeUnmount, ref } from 'vue';

const visible = defineModel<boolean>({
  default: false,
});

const props = withDefaults(defineProps<Props>(), {
  opacityWhenVisible: 0.8,
});

const ghost = ref<HTMLElement | null>(null);
const x = ref<number>(0);
const y = ref<number>(0);

onBeforeMount(() => {
  document.addEventListener('pointermove', onPointerMove);
});

onBeforeUnmount(() => {
  document.removeEventListener('pointermove', onPointerMove);
});

const onPointerMove = (e: PointerEvent) => {
  e.preventDefault();
  e.stopPropagation();

  updateGhost(e.clientX, e.clientY);
};

const updateGhost = (posX: number, posY: number) => {
  if (!ghost.value) return;

  const rect = ghost.value.getBoundingClientRect();
  const screenWidth = window.innerWidth;
  const screenHeight = window.innerHeight;

  //Update position
  x.value = Math.max(
    Math.min(posX, screenWidth - rect.width - SCREEN_MARGIN),
    SCREEN_MARGIN,
  );
  y.value = Math.max(
    Math.min(posY, screenHeight - rect.height - SCREEN_MARGIN),
    SCREEN_MARGIN,
  );
};
</script>

<template>
  <div
    ref="ghost"
    aria-hidden="true"
    class="bms-ghost"
    :style="{
      '--ghost-x': `${x}px`,
      '--ghost-y': `${y}px`,
      opacity: visible ? props.opacityWhenVisible : 0,
    }"
  >
    <slot />
  </div>
</template>

<style scoped lang="scss">
.bms-ghost {
  position: fixed;
  top: var(--ghost-y, 0);
  left: var(--ghost-x, 0);
  z-index: 1000;

  pointer-events: none;
  user-select: none;
  transition: opacity 0.2s ease-in-out;
}
</style>
