<template>
  <view class="zbPopover" :style="{
    '--theme-bg-color': bgStyleColor
  }">
    <view class="mask" @click.stop="close" v-if="show" :style="{ backgroundColor: overlayBg }"></view>
    <view @click.stop="handleClick" class="zb-button-popover">
      <slot></slot>
    </view>
    <view class="zb-popover" v-show="inited" ref="zb-transition" :class="[classes, `zb-popover-${placement}`]"
      :style="[mergeStyle, { ...popoverStyle }]" @touchmove="noop">
      <view class="zb-popover-arrow" :style="[arrowStyle]" :class="[{
        'zb_popper__up': placement.indexOf('bottom') === 0,
        'zb_popper__arrow': placement.indexOf('top') === 0,
        'zb_popper__right': placement.indexOf('right') === 0,
        'zb_popper__left': placement.indexOf('left') === 0,
      }]" v-if="isArrow">
      </view>
      <slot name="content">
        <view :class="[{
          'horizontal__action': actionsDirection === 'horizontal'
        }]">
          <view @click.stop="actionAction(item)" v-for="item, index in options" class="zb-popover__action" :class="[{
            'dark__action': theme === 'dark'
          }]" :key="index">
            <slot name="item" :item="item">
              <i class="icon-font" :class="item.icon" :style="{ fontSize: iconSize }"></i>
            </slot>
            <view class="zb-popover__action-text">
              <trans class="text" :_t="keyName ? item[keyName] : item" />
            </view>
          </view>
        </view>
      </slot>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted, computed, nextTick, watch } from "vue"
const tranClass = {
  enter: "zb-fade-zoom-enter zb-fade-zoom-enter-active",
  'enter-to': "zb-fade-zoom-enter-to zb-fade-zoom-enter-active",
  leave: "zb-fade-zoom-leave zb-fade-zoom-leave-active",
  'leave-to': "zb-fade-zoom-leave-to zb-fade-zoom-leave-active",
}
const props = defineProps({
  options: {
    type: Array,
    default: () => []
  },
  placement: {
    type: String,
    default: 'bottom-start'
  },
  bgColor: {
    type: String,

  },
  theme: {
    type: String,
    default: 'light' // light dark
  },
  actionsDirection: {
    type: String,
    default: 'vertical' // horizontal vertical
  },
  keyName: {
    type: String,
    default: ''
  },
  overlayBg: {
    type: String,
    default: 'transparent'
  },
  iconSize: {
    type: String,
    default: '30px'
  },
  isArrow: Boolean
})


const emit = defineEmits(['handleClick', 'select'])
const show = ref(false);
const inited = ref(false);
const classes = ref('');
const duration = ref(100);
const popoverStyle = ref({});
const arrowOldStyle = ref({});



const bgStyleColor = computed(() => {
  if (props.bgColor) {
    return props.bgColor
  }
  if (props.theme === 'light') {
    return 'white'
  }
  if (props.theme === 'dark') {
    return '#4a4a4a'
  }
})
const mergeStyle = computed(() => {
  return {
    transitionDuration: `${duration.value}ms`,
    transitionTimingFunction: `ease-out`,
    ...popoverStyle.value
  }
})
const arrowStyle = computed(() => {
  return { ...arrowOldStyle.value }
})
onMounted(() => {
  // // #ifdef H5
  // window.addEventListener('click', () => {
  //   show.value = false
  // })
  // // #endif  

})
const handleClick = () => {
  if (show.value) {
    show.value = false
  } else {
    show.value = true
  }
  emit('handleClick', show.value)
}
const close = () => {
  show.value = false
}
const actionAction = (item) => {
  emit('select', item)
  show.value = false
}
const sleep = (value) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, value)
  })
}
const vueEnter = () => {
  inited.value = true
  getPosition()
  classes.value = tranClass.enter
  nextTick(async () => {
    await sleep(30)
    classes.value = tranClass['enter-to']

  })
}
const vueLeave = () => {
  classes.value = tranClass.leave
  nextTick(async () => {
    classes.value = tranClass['leave-to']
    await sleep(120)
    inited.value = false
  })
}

const preventEvent = (e) => {
  e && typeof (e.stopPropagation) === 'function' && e.stopPropagation()
}

const getPosition = () => {
  return new Promise((resolve) => {
    nextTick(() => {
      let selectorQuery = uni.createSelectorQuery().in(this).selectAll('.zb-button-popover,.zb-popover')
      let popoverStyles = {}
      let arrowOldStyles = {}
      selectorQuery.boundingClientRect(async (data) => {
        let { left, bottom, right, top, width, height } = data[0]
        let popoverClientRect = data[1]

        switch (props.placement) {
          case 'top':
            if (popoverClientRect.width > width) {
              popoverStyles.left = `-${(popoverClientRect.width - width) / 2}px`
            } else {
              popoverStyles.left = `${Math.abs(popoverClientRect.width - width) / 2}px`
            }
            popoverStyles.bottom = `${height + 8}px`
            arrowOldStyles.left = (popoverClientRect.width / 2 - 6) + 'px'
            break;
          case 'top-start':
            popoverStyles.left = `0px`
            popoverStyles.bottom = `${height + 8}px`
            arrowOldStyles.left = '16px'
            break;
          case 'top-end':
            popoverStyles.right = `0px`
            popoverStyles.bottom = `${height + 8}px`
            arrowOldStyles.right = '16px'
            break;
          case 'bottom':
            if (popoverClientRect.width > width) {
              popoverStyles.left = `-${(popoverClientRect.width - width) / 2}px`
            } else {
              popoverStyles.left = `${Math.abs(popoverClientRect.width - width) / 2}px`
            }
            popoverStyles.top = `${height + 8}px`
            arrowOldStyles.left = (popoverClientRect.width / 2 - 6) + 'px'
            break;
          case 'bottom-start':
            popoverStyles.top = `${height + 8}px`
            popoverStyles.left = `0px`
            arrowOldStyles.left = '16px'
            break;
          case 'bottom-end':
            popoverStyles.top = `${height + 8}px`
            popoverStyles.right = `0px`
            arrowOldStyles.right = '16px'
            break;
          case 'right':
            popoverStyles.left = `${width + 8}px`
            if (popoverClientRect.height > height) {
              popoverStyles.top = `-${(popoverClientRect.height - height) / 2}px`
            } else {
              popoverStyles.top = `${Math.abs((popoverClientRect.height - height) / 2)}px`
            }
            arrowOldStyles.top = `${popoverClientRect.height / 2 - 6}px`
            break;
          case 'right-start':
            popoverStyles.left = `${width + 8}px`
            popoverStyles.top = `0px`
            arrowOldStyles.top = `8px`
            break;
          case 'right-end':
            popoverStyles.left = `${width + 8}px`
            popoverStyles.bottom = `0px`
            arrowOldStyles.bottom = `8px`
            break;
          case 'left':
            popoverStyles.right = `${width + 8}px`
            if (popoverClientRect.height > height) {
              popoverStyles.top = `-${(popoverClientRect.height - height) / 2}px`
            } else {
              popoverStyles.top = `${Math.abs((popoverClientRect.height - height) / 2)}px`
            }
            arrowOldStyles.top = `${popoverClientRect.height / 2 - 6}px`
            break;
          case 'left-start':
            popoverStyles.right = `${width + 8}px`
            popoverStyles.top = `0px`
            arrowOldStyles.top = `8px`
            break;
          case 'left-end':
            popoverStyles.right = `${width + 8}px`
            popoverStyles.bottom = `0px`
            arrowOldStyles.bottom = `8px`
            break;
        }
        popoverStyle.value = popoverStyles;
        arrowOldStyle.value = arrowOldStyles
        resolve()
      }).exec()
    })
  })
}

const noop = (e) => {
  preventEvent(e)
}

watch(show, (newVal) => {
  newVal ? vueEnter() : vueLeave()
}, { immediate: true })
</script>

<style lang="scss" scoped>
$theme-bg-color: var(--theme-bg-color);

.mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2044;
}

.zbPopover {
  position: relative;
}

.zb-button-popover {
  display: flex;
  align-items: center;
}

.zb-popover {
  border-radius: 8px;
  z-index: 2144;
  position: absolute;
  background-color: $theme-bg-color;
  box-shadow: 0 2px 12px #3232331f;
  overflow: hidden;
}

.zb-popover-top {
  transform-origin: 50% bottom;
}

.zb-popover-top-start {
  transform-origin: 50% bottom;
}

.zb-popover-top-end {
  transform-origin: 0 bottom;
}

.zb-popover-bottom {
  transform-origin: 50% 0;
}

.zb-popover-bottom-end {
  transform-origin: 100% 0;
}

.zb-popover-bottom-start {
  transform-origin: 0 0;
}

.zb-popover-right {
  transform-origin: left 50%;
}

.zb-popover-right-start {
  transform-origin: left 0;
}

.zb-popover-right-end {
  transform-origin: left 100%;
}

.zb-popover-left {
  transform-origin: right 50%;
}

.zb-popover-left-start {
  transform-origin: right 0;
}

.zb-popover-left-end {
  transform-origin: right 100%;
}

.zb-popover-arrow {
  position: absolute;
  width: 0;
  height: 0;
  border-color: transparent;
  border-style: solid;
  border-width: 6px;
  color: $theme-bg-color;
}

.zb_popper__up {
  border-top-width: 0;
  border-bottom-color: currentColor;
  top: -5px;
}

.zb_popper__right {
  border-left-width: 0;
  border-right-color: currentColor;
  left: -5px;
}

.zb_popper__left {
  border-right-width: 0;
  border-left-color: currentColor;
  right: -5px;
}

.zb_popper__arrow {
  border-bottom-width: 0;
  border-top-color: currentColor;
  bottom: -6px;
}

.zb-popover__action {
  position: relative;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  height: 88rpx;
  padding: 0 24rpx;
  font-size: 28rpx;
  cursor: pointer;
}

.zb-popover__action-text {
  display: flex;
  flex: 1;
  align-items: center;
  height: 100%;
  padding: 0 24rpx;
  // border-bottom: 1rpx solid #ebedf0;
  word-wrap: break-word;
  white-space: nowrap;
  .text{
    display: inline-block;
    word-wrap: break-word;
    white-space: nowrap;
    color: #62708c;
  }
}

.zb-popover__action:last-child {
  .zb-popover__action-text {
    border-bottom: none;
  }
}

.dark__action {
  color: white;

  .zb-popover__action-text {
    // border-bottom: 1rpx solid #ebedf033
  }
}

.horizontal__action {
  display: flex;

  .zb-popover__action {
    padding: 0 20rpx;
    border-right: 1rpx solid #ebedf0;
  }

  .zb-popover__action-text {
    padding: 0;
    //border-right:1rpx solid #ebedf0;
  }
}


$u-zoom-scale: scale(0.95);

.zb-fade-enter-active,
.zb-fade-leave-active {
  transition-property: opacity;
}

.zb-fade-enter,
.zb-fade-leave-to {
  opacity: 0
}

.zb-fade-zoom-enter,
.zb-fade-zoom-leave-to {
  transform: $u-zoom-scale;
  opacity: 0;
}

.zb-fade-zoom-enter-active,
.zb-fade-zoom-leave-active {
  transition-property: transform, opacity;
}

.zb-fade-down-enter-active,
.zb-fade-down-leave-active,
.zb-fade-left-enter-active,
.zb-fade-left-leave-active,
.zb-fade-right-enter-active,
.zb-fade-right-leave-active,
.zb-fade-up-enter-active,
.zb-fade-up-leave-active {
  transition-property: opacity, transform;
}

.zb-fade-up-enter,
.zb-fade-up-leave-to {
  transform: translate3d(0, 100%, 0);
  opacity: 0
}

.zb-fade-down-enter,
.zb-fade-down-leave-to {
  transform: translate3d(0, -100%, 0);
  opacity: 0
}

.zb-fade-left-enter,
.zb-fade-left-leave-to {
  transform: translate3d(-100%, 0, 0);
  opacity: 0
}

.zb-fade-right-enter,
.zb-fade-right-leave-to {
  transform: translate3d(100%, 0, 0);
  opacity: 0
}


.zb-popover__action {
  .icon-font {
    color: #62708c;
  }

  &:active {
    background-color: rgba(0, 0, 0, 0.2);
  }

  &--disabled {
    color: var(--van-popover-dark-action-disabled-text-color);

    &:active {
      background-color: transparent;
    }
  }
}
</style>
