<template>
  <span
    ref="hintRoot"
    class="field-hint"
    tabindex="0"
    :aria-describedby="popoverId"
    @mouseenter="showPopover"
    @mouseleave="hidePopover"
    @focus="showPopover"
    @blur="hidePopover"
    @keydown.escape="hidePopover"
  >
    <AppIcon name="warning" tone="warning" stroke-width="1.6" />
    <Teleport to="body">
      <span
        v-if="popoverVisible"
        :id="popoverId"
        ref="hintPopover"
        class="field-hint-popover"
        :class="{
          'field-hint-popover-open': popoverPositioned,
          'field-hint-popover-bottom': popoverPlacement === 'bottom'
        }"
        :style="popoverStyle"
        role="tooltip"
      >
        {{ text }}
      </span>
    </Teleport>
  </span>
</template>

<script setup>
import { nextTick, ref, useId } from "vue";

import AppIcon from "./AppIcon.vue";

defineProps({
  text: {
    type: String,
    required: true
  }
});

const popoverId = `field-hint-${useId()}`;
const hintRoot = ref(null);
const hintPopover = ref(null);
const popoverVisible = ref(false);
const popoverPositioned = ref(false);
const popoverPlacement = ref("top");
const popoverStyle = ref({});

async function showPopover() {
  popoverVisible.value = true;
  popoverPositioned.value = false;
  await nextTick();
  updatePopoverPosition();
  popoverPositioned.value = true;
}

function hidePopover() {
  popoverVisible.value = false;
  popoverPositioned.value = false;
}

function updatePopoverPosition() {
  if (!hintRoot.value || !hintPopover.value) {
    return;
  }

  const viewportPadding = 12;
  const gap = 10;
  const rootRect = hintRoot.value.getBoundingClientRect();
  const popoverRect = hintPopover.value.getBoundingClientRect();
  const maxWidth = Math.max(160, Math.min(280, window.innerWidth - viewportPadding * 2));
  const width = Math.min(popoverRect.width || maxWidth, maxWidth);
  const height = popoverRect.height || 40;
  const rootCenter = rootRect.left + rootRect.width / 2;
  const left = Math.min(Math.max(rootCenter - width / 2, viewportPadding), window.innerWidth - width - viewportPadding);
  let top = rootRect.top - height - gap;
  let placement = "top";

  if (top < viewportPadding) {
    top = rootRect.bottom + gap;
    placement = "bottom";
  }

  popoverPlacement.value = placement;
  popoverStyle.value = {
    left: `${Math.round(left)}px`,
    top: `${Math.round(top)}px`,
    maxWidth: `${Math.round(maxWidth)}px`,
    "--field-hint-arrow-left": `${Math.round(rootCenter - left)}px`
  };
}
</script>
