<template>
  <Teleport to="body">
    <UiTooltip
      v-if="showToolTip && activated"
      :visible="showToolTip && activated"
      :direction="direction"
      :getAnchorElementValues="getAnchorElementValues"
      :class="classes"
    >
      <slot name="tooltipText">
        {{ tooltipText }}
      </slot>
    </UiTooltip>
  </Teleport>

  <div
    ref="tooltipAnchor"
    class="bms-tooltip-anchor-wrapper"
    v-if="activated"
    @mouseenter="isAnchorUncovered() && toggleTooltip(true)"
    @mouseleave="toggleTooltip(false)"
  >
    <slot></slot>
  </div>

  <slot v-if="!activated"></slot>
</template>

<script setup lang="ts">
import { TooltipDirection } from '@/models';
import { computed, inject, onUnmounted, ref } from 'vue';
import UiTooltip from './UiTooltip.vue';

import { useAttrs } from 'vue';
const attrs = useAttrs();

const inModal = inject('bms-in-modal', false);

const tooltipAnchor = ref<Element>();
const showToolTip = ref(false);

withDefaults(
  defineProps<{
    tooltipText?: string;
    direction?: TooltipDirection;
    focus?: boolean;
    activated?: boolean;
  }>(),
  {
    tooltipText: '',
    direction: TooltipDirection.Bottom,
    focus: false,
    activated: true,
  },
);

const classes = computed(() => {
  const parentClasses = attrs.class as string | undefined;
  const baseClasses =
    parentClasses
      ?.split(' ')
      .map((cls) => `${cls}__bms-tooltip`)
      .join(' ') ?? '';
  return inModal ? `${baseClasses} bms-in-modal`.trim() : baseClasses;
});

const isAnchorUncovered = (): boolean => {
  if (!tooltipAnchor.value) return false;
  const { top, left, right, bottom, width, height } =
    tooltipAnchor.value.getBoundingClientRect();
  const inset = 1;
  const points = [
    { x: left + width / 2, y: top + height / 2 },
    { x: left + inset, y: top + inset },
    { x: right - inset, y: top + inset },
    { x: left + inset, y: bottom - inset },
    { x: right - inset, y: bottom - inset },
  ];
  return points.every(({ x, y }) => {
    const el = document.elementFromPoint(x, y);
    return el !== null && tooltipAnchor.value!.contains(el);
  });
};

const onDocumentPointerMove = () => {
  if (!isAnchorUncovered()) {
    toggleTooltip(false);
  }
};

const getAnchorElementValues = () => {
  if (!tooltipAnchor.value) return;
  const { top, bottom, left, right, width, height } =
    tooltipAnchor.value.getBoundingClientRect();

  return {
    top: top + window.scrollY,
    left: left + window.scrollX,
    right,
    bottom,
    width,
    height,
  };
};

function toggleTooltip(state: boolean) {
  showToolTip.value = state;
  if (state) {
    document.addEventListener('pointermove', onDocumentPointerMove, {
      passive: true,
    });
  } else {
    document.removeEventListener('pointermove', onDocumentPointerMove);
  }
}

onUnmounted(() => {
  document.removeEventListener('pointermove', onDocumentPointerMove);
});

defineExpose({
  toggle: toggleTooltip,
});
</script>

<style lang="scss" scoped>
.bms-tooltip-anchor-wrapper {
  position: relative;
  display: inline-block;
  outline: none;
}
</style>
