<script setup>
import { reactiveOmit } from "@vueuse/core";
import { Icon } from "@iconify/vue";
import { useForwardProps } from "reka-ui";
import { onBeforeUnmount, shallowRef, watchEffect } from "vue";
import {
  DrawerClose,
  DrawerContent,
  DrawerPortal
} from "vaul-vue";
import { cn } from "../../../utils/cn";
import DrawerOverlay from "./DrawerOverlay.vue";
defineOptions({
  inheritAttrs: false
});
const props = defineProps({
  class: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
  showCloseButton: { type: Boolean, required: false, default: true }
});
const emit = defineEmits(["after-close"]);
const delegatedProps = reactiveOmit(props, "class", "showCloseButton");
const forwardedProps = useForwardProps(delegatedProps);
const scrollElement = shallowRef(null);
const contentElement = shallowRef(null);
let closeFallbackTimer;
let hasEmittedAfterClose = false;
function isClosedContentTarget(target) {
  return target instanceof HTMLElement && target.dataset.state === "closed";
}
function clearCloseFallbackTimer() {
  if (closeFallbackTimer === void 0) {
    return;
  }
  window.clearTimeout(closeFallbackTimer);
  closeFallbackTimer = void 0;
}
function emitAfterClose() {
  if (hasEmittedAfterClose) {
    return;
  }
  hasEmittedAfterClose = true;
  clearCloseFallbackTimer();
  emit("after-close");
}
function parseDurationMs(value) {
  const normalizedValue = value.trim();
  if (normalizedValue.endsWith("ms")) {
    const duration = Number.parseFloat(normalizedValue.slice(0, -2));
    return Number.isFinite(duration) ? duration : 0;
  }
  if (normalizedValue.endsWith("s")) {
    const duration = Number.parseFloat(normalizedValue.slice(0, -1));
    return Number.isFinite(duration) ? duration * 1e3 : 0;
  }
  return 0;
}
function getLongestMotionMs(element) {
  const style = window.getComputedStyle(element);
  const animationDurations = style.animationDuration.split(",");
  const animationDelays = style.animationDelay.split(",");
  const transitionDurations = style.transitionDuration.split(",");
  const transitionDelays = style.transitionDelay.split(",");
  let longestMotionMs = 0;
  for (const [index, durationValue] of animationDurations.entries()) {
    const durationMs = parseDurationMs(durationValue);
    const delayMs = parseDurationMs(animationDelays[index] ?? animationDelays[0] ?? "0s");
    longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
  }
  for (const [index, durationValue] of transitionDurations.entries()) {
    const durationMs = parseDurationMs(durationValue);
    const delayMs = parseDurationMs(transitionDelays[index] ?? transitionDelays[0] ?? "0s");
    longestMotionMs = Math.max(longestMotionMs, durationMs + delayMs);
  }
  return longestMotionMs;
}
function syncCloseFallback() {
  const element = contentElement.value;
  clearCloseFallbackTimer();
  if (!element) {
    return;
  }
  if (element.dataset.state !== "closed") {
    hasEmittedAfterClose = false;
    return;
  }
  const motionMs = getLongestMotionMs(element);
  closeFallbackTimer = window.setTimeout(() => {
    emitAfterClose();
  }, motionMs > 0 ? motionMs : 0);
}
function handleCloseMotionEnd(event) {
  if (hasEmittedAfterClose || event.target !== event.currentTarget || !isClosedContentTarget(event.currentTarget)) {
    return;
  }
  emitAfterClose();
}
function setContentElement(target) {
  if (target instanceof HTMLElement) {
    contentElement.value = target;
    syncCloseFallback();
    return;
  }
  if (target && "$el" in target && target.$el instanceof HTMLElement) {
    contentElement.value = target.$el;
    syncCloseFallback();
    return;
  }
  contentElement.value = null;
  clearCloseFallbackTimer();
}
watchEffect((onCleanup) => {
  const element = contentElement.value;
  if (!element) {
    return;
  }
  const observer = new MutationObserver(() => {
    syncCloseFallback();
  });
  observer.observe(element, {
    attributes: true,
    attributeFilter: ["data-state"]
  });
  syncCloseFallback();
  onCleanup(() => {
    observer.disconnect();
  });
});
onBeforeUnmount(() => {
  clearCloseFallbackTimer();
});
let touchStartY = 0;
let touchStartedAtTop = false;
function handleScrollTouchStart(event) {
  touchStartY = event.touches[0].clientY;
  touchStartedAtTop = (scrollElement.value?.scrollTop ?? 0) <= 0;
}
function handleScrollTouchMove(event) {
  if (!touchStartedAtTop) return;
  const currentY = event.touches[0].clientY;
  if (currentY > touchStartY) {
    event.preventDefault();
  }
}
</script>

<template>
  <DrawerPortal>
    <DrawerOverlay />
    <DrawerContent
      :ref="setContentElement"
      data-slot="drawer-content"
      v-bind="{ ...$attrs, ...forwardedProps }"
      :class="
  cn(
    'data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[90vh] flex-col gap-4 rounded-t-lg border border-zinc-200 bg-white p-6 shadow-lg outline-hidden',
    props.class
  )
"
      @animationend="handleCloseMotionEnd"
      @transitionend="handleCloseMotionEnd"
    >
      <div class="mx-auto -mt-2 h-2 w-16 rounded-full bg-zinc-200" />

      <div
        ref="scrollElement"
        class="min-h-0 flex-1 overflow-y-auto overscroll-contain"
        @touchstart.passive="handleScrollTouchStart"
        @touchmove="handleScrollTouchMove"
      >
        <slot />
      </div>

      <DrawerClose
        v-if="showCloseButton"
        data-slot="drawer-close-button"
        class="data-[state=open]:bg-zinc-100 data-[state=open]:text-zinc-700 absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
      >
        <Icon icon="fluent:dismiss-20-filled" />
        <span class="sr-only">Close</span>
      </DrawerClose>
    </DrawerContent>
  </DrawerPortal>
</template>
