import { onUnmounted, ref, unref, watch, type MaybeRef, type Ref } from 'vue';
import { bindVHover, detachVHover, type VHoverBindingValue } from './vHover';

/**
 * Programmatic v-hover: bind the returned ref to a root element; the overlay is synced to `variant`
 * with the same semantics as the `v-hover` directive.
 * @param variant - Hover overlay binding: `'subtle' | 'default' | 'strong'`, `{ variant: ... }`, or
 *   `false` / `null` / `undefined` to leave the element without an overlay when not disabled.
 *   May be a ref or other {@link MaybeRef} source.
 * @param isDisabled - When `true`, the overlay is removed and not re-attached until `false`.
 *   May be a ref or other {@link MaybeRef} source. Defaults to `false`.
 * @returns Ref to assign to the target root element (e.g. `<button ref="hoverRef">`).
 * @example
 * ```vue
 * <script setup lang="ts">
 *   const hoverRef = useVHover('default');
 * </script>
 * <template>
 *   <button ref="hoverRef" type="button">OK</button>
 * </template>
 * ```
 * @example
 * ```ts
 * const hoverRef = useVHover('subtle', computed(() => props.disabled));
 * ```
 */
export function useVHover(
  variant: MaybeRef<VHoverBindingValue>,
  isDisabled: MaybeRef<boolean> = false,
): Ref<HTMLElement | null> {
  const targetRef = ref<HTMLElement | null>(null);
  let boundEl: HTMLElement | null = null;

  watch(
    [targetRef, () => unref(variant), () => Boolean(unref(isDisabled))],
    () => {
      const el = targetRef.value;
      const disabled = Boolean(unref(isDisabled));

      if (boundEl && boundEl !== el) {
        detachVHover(boundEl);
        boundEl = null;
      }

      if (!el) return;

      if (disabled) {
        detachVHover(el);
        boundEl = null;
        return;
      }

      bindVHover(el, unref(variant));
      boundEl = el;
    },
    { flush: 'post', immediate: true },
  );

  onUnmounted(() => {
    if (boundEl) {
      detachVHover(boundEl);
      boundEl = null;
    }
  });

  return targetRef;
}
