<template>
  <Transition name="test">
    <div
      v-if="modelValue"
      ref="dialog"
      :class="['FromBottomDialog', mode, showHengGang ? '' : 'no-heng-gang']"
      @touchstart="onStart"
      @touchmove="onMove"
      @touchend="onEnd"
    >
      <slot name="header" />
      <div v-if="showHengGang" :class="['heng-gang', mode]">
        <div class="content" />
      </div>
      <div ref="wrapper" class="wrapper">
        <slot />
      </div>
    </div>
  </Transition>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import Dom, { _css } from '@/utils/dom'
import bus, { EVENT_KEY } from '@/utils/bus'
import { _stopPropagation } from '@/utils'

const props = withDefaults(
  defineProps<{
    modelValue?: boolean
    mode?: 'dark' | 'light' | 'white'
    maskMode?: 'dark' | 'light' | 'white'
    height?: string
    showHengGang?: boolean
    pageId: string
    tag?: string
  }>(),
  {
    modelValue: false,
    mode: 'dark',
    maskMode: 'dark',
    height: 'calc(var(--vh, 1vh) * 70)',
    showHengGang: true,
    tag: '',
  },
)

const emit = defineEmits<{
  'update:modelValue': [boolean]
  cancel: []
}>()

const dialog = ref<HTMLElement | null>(null)
const wrapper = ref<HTMLElement | null>(null)
const scroll = ref(0)
const startY = ref(0)
const moveY = ref(0)
const startTime = ref(0)
const pagePosition = ref<string | null>(null)

watch(
  () => props.modelValue,
  (newVal) => {
    const page = document.getElementById(props.pageId)
    if (!page) return
    if (newVal) {
      pagePosition.value = String(_css(page, 'position') ?? '')
      page.style.position = 'absolute'
      scroll.value = document.documentElement.scrollTop
      document.body.style.position = 'fixed'
      document.body.style.top = `-${scroll.value}px`

      const mask = new Dom().create(`<div class="Mask fade-in ${props.maskMode}"></div>`)
      setTimeout(() => {
        mask.on('click', (e: Event) => {
          _stopPropagation(e)
          onHide()
        })
      }, 200)
      new Dom(page).append(mask)
    } else {
      page.style.position = pagePosition.value || 'fixed'
      document.body.style.position = 'static'
      document.documentElement.scrollTop = scroll.value
      const mask = new Dom('.Mask').replaceClass('fade-in', 'fade-out')
      setTimeout(() => mask.remove(), 250)
    }
  },
)

function onHide() {
  emit('update:modelValue', false)
  emit('cancel')
}

function onStart(e: TouchEvent) {
  if (wrapper.value?.scrollTop !== 0) return
  startY.value = e.touches[0].clientY
  startTime.value = Date.now()
  if (dialog.value) _css(dialog.value, 'transition-duration', '0ms')
}

function onMove(e: TouchEvent) {
  if (wrapper.value?.scrollTop !== 0) return
  moveY.value = e.touches[0].pageY - startY.value
  if (moveY.value > 0 && dialog.value) {
    bus.emit(EVENT_KEY.DIALOG_MOVE, { tag: props.tag, e: moveY.value })
    _css(dialog.value, 'transform', `translate3d(0, ${moveY.value}px, 0)`)
  }
}

function onEnd() {
  if (!dialog.value) return
  if (Date.now() - startTime.value < 150 && Math.abs(moveY.value) < 30) return
  const clientHeight = dialog.value.clientHeight
  _css(dialog.value, 'transition-duration', '250ms')
  if (Math.abs(moveY.value) > clientHeight / 2) {
    _css(dialog.value, 'transform', 'translate3d(0,100%,0)')
    bus.emit(EVENT_KEY.DIALOG_END, { tag: props.tag, isClose: true })
    setTimeout(onHide, 250)
  } else {
    _css(dialog.value, 'transform', 'translate3d(0,0,0)')
    bus.emit(EVENT_KEY.DIALOG_END, { tag: props.tag, isClose: false })
  }
  moveY.value = 0
}
</script>

<style scoped lang="less">
.test-enter-active,
.test-leave-active {
  transition-duration: 250ms !important;
}

.test-enter-from,
.test-leave-to {
  transform: translate3d(0, 101%, 0) !important;
}

.FromBottomDialog {
  z-index: 9;
  position: fixed;
  width: 100%;
  padding-top: 24rem;
  bottom: 0;
  left: 0;
  box-sizing: border-box;
  border-radius: 15rem 15rem 0 0;
  transform: translate3d(0, 0, 0);
  overflow: hidden;
  display: flex;
  height: v-bind(height);
  max-height: v-bind(height);
  flex-direction: column;

  &.white {
    background: white;
  }

  &.no-heng-gang {
    padding-top: 0;
  }

  .heng-gang {
    border-radius: 15rem 15rem 0 0;
    z-index: 3;
    width: 100%;
    position: fixed;
    height: 30rem;
    display: flex;
    transform: translateY(-24rem);
    justify-content: center;
    align-items: center;
    touch-action: pan-y;
    background: white;

    .content {
      border-radius: 2px;
      height: 4rem;
      width: 30rem;
      background: darkgray;
    }
  }

  .wrapper {
    flex: 1;
    overflow: auto;
  }
}
</style>
