<script setup lang="ts">

import { twJoin, twMerge } from 'tailwind-merge'
import { onClickOutside, useWindowSize } from '@vueuse/core'
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'

const uiConfig = {
  wrapper: 'modal-wrapper relative z-[10001]',
  overlay: {
    base: 'fixed inset-0 transition-opacity ',
    background: "bg-deepblue-900/20 dark:bg-white/20 backdrop-blur",
    transition: {
      'enter-active-class': "ease-out duration-300",
      'enter-from-class': "opacity-0",
      'enter-to-class': "opacity-100",
      'leave-active-class': "ease-in duration-200",
      'leave-from-class': "opacity-100",
      'leave-to-class': "opacity-0"
    },
  },
  base: 'base-modal max-h-full fixed text-deepblue-900 dark:text-gray-200 text-left rtl:text-right flex flex-col max-w-full sm:max-h-[calc(100%-48px)]',
  position: 'top-1/2 left-1/2 translate-y-[-50%] translate-x-[-50%]',
  padding: "p-8",
  background: "bg-white dark:bg-gray-900",
  rounded: "rounded-lg",
  fullscreen: "w-screen h-screen rounded-none",
  mobile: {
    width: "w-screen",
    position: "bottom-0 left-0 transition-transform",
    padding: 'px-4 sm:pb-8 pb-4 pt-3',
    rounded: "rounded-t-2xl"
  },
  transition: {
    desktop: {
      'enter-active-class': "ease-out duration-300",
      'enter-from-class': "opacity-0 bg",
      'enter-to-class': "opacity-100",
      'leave-active-class': "ease-in duration-200",
      'leave-from-class': "opacity-100",
      'leave-to-class': "opacity-0"
    },
    mobile: {
      'enter-active-class': "transition-transform ease-in-out duration-300",
      'leave-active-class': "transition-transform ease-in-out duration-200",
      'enter-from-class': "translate-y-[100%]",
      'leave-to-class': "translate-y-[100%]"
    }
  }
}

interface Props {
  title?: string
  transition?: boolean
  overlay?: boolean
  preventClose?: boolean
  fullscreen?: boolean
  name?: string
  isScrollable?: boolean
  width?: string | number
  heightModalClass?: string
}

const props = withDefaults(defineProps<Props>(), {
  title: '',
  transition: true,
  overlay: true,
  preventClose: false,
  fullscreen: false,
  isScrollable: false,
  name: 'modal',
  width: 424,
  heightModalClass: '',
})
const content = ref()

const emit = defineEmits(['close'])

const slots = useSlots()

const {width} = useWindowSize()
const modelValue = defineModel<boolean>()
let teleportContainer: HTMLBodyElement | HTMLDivElement | undefined
const modal = ref<HTMLDivElement | null>(null)

const isMobile = computed(() => width.value < 1025)

const wrapperClasses = uiConfig.wrapper
const overlayClasses = computed(() => !props.overlay || twMerge(twJoin(uiConfig.overlay.base, uiConfig.overlay.background)))
const baseClasses = computed(() => twMerge(twJoin(
  uiConfig.base,
  uiConfig.background,
  props.heightModalClass,
  props.fullscreen ? uiConfig.fullscreen : '',
  isMobile.value ? uiConfig.mobile.padding : uiConfig.padding,
  isMobile.value ? uiConfig.mobile.rounded : uiConfig.rounded,
  isMobile.value ? uiConfig.mobile.width : '',
  isMobile.value ? uiConfig.mobile.position : uiConfig.position
)))
const transitionClasses = computed(() => {
  return {
    overlay: props.transition ? uiConfig.overlay.transition : {},
    base: props.transition ? (!isMobile.value ? uiConfig.transition.desktop : uiConfig.transition.mobile) : {}
  }
})

const modalStyles = computed(() => {
  if (props.fullscreen || isMobile.value) return
  return ` width: ${props.width}${typeof props.width === 'number' ? 'px' : ''}`;
})

const onClose = () => {
  modelValue.value = false
  emit('close')
}

onClickOutside(modal, () => props.preventClose || onClose())

type Slot = 'footer' | 'header'

const hasSlot = (name: Slot): boolean => {
  return Boolean(slots[name])
}

const hasFooter = computed(() => {
  return hasSlot('footer')
})

const hasHeader = computed(() => {
  return props.title || hasSlot('header')
})

const hasContent = computed(() => {
  return Boolean(slots.default)
})

onBeforeMount(() => {
  const alreadyCreatedTarget = document.getElementById(props.name)
  if (alreadyCreatedTarget) return
  teleportContainer = document.createElement('div')
  teleportContainer.setAttribute('id', props.name)
  document.body.appendChild(teleportContainer)
})


// Mobile swipe close

const positionStart = ref<number>(0)
const isClose = ref<boolean>(false)
const modalHeight = ref(0)

const touchstart = (event: TouchEvent) => {
  isClose.value = false
  positionStart.value = event.touches[0].clientY
  modalHeight.value = modal.value?.offsetHeight || 0 // Запоминаем текущую высоту модалки
}

const touchmove = (event: TouchEvent) => {
  if (!isMobile.value) return;
  event.preventDefault();
  const touchPosition = event.touches[0].clientY
  const step = touchPosition - positionStart.value

  if (step < 0) return // предотвратить движение вверх

  const newHeight = modalHeight.value - step
  modal.value.style.height = `${newHeight}px`
  isClose.value = step > 65
}


const touchend = () => {
  if (isClose.value) {
    onClose()
  } else {
    modal.value.style.height = `${modalHeight.value}px`
  }
}
const toggleBodyScroll = (lock: boolean) => {
  if (!content.value) return
  if (lock) {
    setTimeout(() => {
      disableBodyScroll(content.value, {
        reserveScrollBarGap: true,
        allowTouchMove: (el: EventTarget | null): boolean => {
          return el && modal.value?.contains(el as Node);
        },
        // allowTouchMove: (el: EventTarget | null): boolean => {
        //   if (!el || !content.value) return false;
        //
        //   // Функция проверки, есть ли у элемента вертикальный скролл
        //   const hasScroll = (el: HTMLElement | null): boolean => {
        //     if (!el) return false;
        //     return el.scrollHeight > el.clientHeight;
        //   };
        //
        //   // Функция поиска блока с position: absolute
        //   const findAbsoluteBlock = (el: HTMLElement | null): HTMLElement | null => {
        //     while (el && el !== content.value) {
        //       const style = window.getComputedStyle(el);
        //       if (style.position === 'absolute') return el; // Возвращаем найденный absolute-элемент
        //       el = el.parentElement;
        //     }
        //     return null;
        //   };
        //
        //   // Проверяем, есть ли у родителя absolute-позиционирование
        //   const someParentHasScroll = (el: HTMLElement | null, maxParentEl: HTMLElement | null): boolean => {
        //     while (el && maxParentEl && el !== maxParentEl) {
        //       if (hasScroll(el)){
        //         return true
        //       } // Если нашли родителя со скроллом, возвращаем true
        //       el = el?.parentElement;
        //     }
        //     return false; // Если не нашли, возвращаем false
        //   };
        //
        //   const absoluteBlock = findAbsoluteBlock(el as HTMLElement);
        //
        //
        //   // Проверяем наличие скролла у основного контента
        //   const contentHasScroll = hasScroll(content.value);
        //
        //   // Проверка на то, что элемент находится внутри модального контента
        //   const isInsideModal = content.value.contains(el as Node);
        //
        //
        //   return (contentHasScroll && isInsideModal) || (isInsideModal && absoluteBlock && someParentHasScroll(el, absoluteBlock));
        // }
        //

      })
    }, 0)

  } else {
    enableBodyScroll(content.value)
  }
}

watch(modelValue, async (newValue) => {
  if (newValue) {
    await nextTick()
    toggleBodyScroll(true)
  } else {
    toggleBodyScroll(false)
  }
})
</script>

<template>
  <client-only>
    <teleport :to="`#${name}`">
      <div
        :class="wrapperClasses"
      >
        <Transition
          name="overlay"
          v-bind="transitionClasses.overlay"
        >
          <div
            v-show="modelValue"
            ref="overlay"
            :class="overlayClasses"
          />
        </Transition>
        <Transition
          name="modal"
          v-bind="transitionClasses.base"
        >
          <div
            v-if="modelValue"
            class="fixed overflow-y-auto inset-0"
          >
            <div
              ref="modal"
              :class="baseClasses"
              :style="modalStyles"
            >
              <div
                v-if="isMobile"
                class="w-full flex justify-center items-center -mt-3 pt-3 mb-2"
                @touchmove="touchmove"
                @touchstart="touchstart"
                @touchend="touchend"
              >
                <div class="h-1 w-10 bg-[#D9D9D9] rounded m-1" />
              </div>
              <div
                class="flex flex-col gap-5"
                :class="isScrollable ? 'overflow-x-hidden': ''"
              >
                <div
                  v-if="hasHeader"
                  class="top"
                >
                  <h4
                    v-if="title"
                    class="heading-02 text-center"
                    @touchmove="touchmove"
                    @touchstart="touchstart"
                    @touchend="touchend"
                  >
                    {{ title }}
                  </h4>
                  <div v-if="!!$slots.header">
                    <slot name="header" />
                  </div>
                </div>
                <div
                  v-if="hasContent"
                  class="grow"
                  ref="content"
                  :class="isScrollable ? 'overflow-x-hidden': ''"
                >
                  <slot />
                </div>
                <div
                  v-if="hasFooter"
                >
                  <slot name="footer" />
                </div>
              </div>
            </div>
          </div>
        </Transition>
      </div>
    </teleport>
  </client-only>
</template>

<style scoped>

</style>
