<template>
  <view class="cwg-droplist">
    <view class="cwg-droplist-trigger" @click.stop="toggleMenu" id="trigger-box">
      <slot></slot>
    </view>

    <!-- 使用 teleport 解决层级遮挡问题 (H5) -->
    <teleport to="body" :disabled="!isTeleportSupported">
      <view
        :id="portalId"
        class="cwg-droplist-portal"
        :class="{ 'is-show': isShow }"
        :style="{ zIndex }"
        @click.stop="closeMenu"
      >
        <view class="cwg-droplist-mask" @click.stop="closeMenu"></view>
        <view
          class="cwg-droplist-menu"
          :class="[`placement-${placement}`]"
          :style="menuStyle"
          @click.stop
        >
          <slot name="dropdown">
            <template v-if="menuList && menuList.length">
              <cwg-droplist-item
                v-for="(item, index) in menuList"
                :key="index"
                :command="item.command !== undefined ? item.command : (item.value !== undefined ? item.value : item)"
                :disabled="item.disabled"
                @click="handleMenuClick(item,index)"
              >
                {{ item.label || item.text || item.title || item }}
              </cwg-droplist-item>
            </template>
          </slot>
        </view>
      </view>
    </teleport>
  </view>
</template>

<script setup>
import { ref, computed, getCurrentInstance, onUnmounted, nextTick } from 'vue'

// 导入 cwg-droplist-item 以便在组件内部直接使用
import CwgDroplistItem from './cwg-droplist-item.vue'

const props = defineProps({
  // 传入的菜单列表，支持简单数组 ['A', 'B'] 或对象数组 [{ label: 'A', command: 'a', disabled: true, row: row }]
  menuList: {
    type: Array,
    default: () => []
  },
  // 菜单弹出位置，支持: bottom, bottom-start, bottom-end, top, top-start, top-end
  placement: {
    type: String,
    default: 'bottom'
  },
  // 距离触发元素的间距 (px)
  offset: {
    type: Number,
    default: 60
  },
  // z-index 层级
  zIndex: {
    type: Number,
    default: 9999
  },
  // 点击菜单项后是否自动隐藏菜单
  hideOnClick: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['visible-change', 'command', 'menuClick'])

const instance = getCurrentInstance()
const isShow = ref(false)
const menuStyle = ref({})

// 检测环境是否支持 Teleport
const isTeleportSupported = computed(() => {
  // #ifdef H5
  return true
  // #endif
  return false
})

// 查询 DOM 节点信息
const queryRect = (selector, context = instance.proxy) => {
  return new Promise((resolve) => {
    uni.createSelectorQuery()
      .in(context)
      .select(selector)
      .boundingClientRect(resolve)
      .exec()
  })
}

// 获取唯一标识符，用于 teleport 查询
const portalId = 'droplist_' + Math.random().toString(36).substr(2, 9)

// 展开/收起菜单
const toggleMenu = async () => {
  if (isShow.value) {
    closeMenu()
  } else {
    await openMenu()
  }
}

// 展开菜单并计算位置
const openMenu = async () => {
  const triggerRectList = await queryRect('.cwg-droplist-trigger')
  const triggerRect = Array.isArray(triggerRectList) ? triggerRectList[0] : triggerRectList
  if (!triggerRect) return

  // 预设菜单显示，获取菜单尺寸
  isShow.value = true
  emit('visible-change', true)
  
  await nextTick()

  let menuRect = null
  // #ifdef H5
  // 在 H5 且 teleport 生效时，需要通过全局原生 API 获取尺寸
  const el = document.querySelector(`#${portalId} .cwg-droplist-menu`)
  if (el) menuRect = el.getBoundingClientRect()
  // #endif
  // #ifndef H5
  let menuRectList = await queryRect('.cwg-droplist-menu', instance.proxy)
  menuRect = Array.isArray(menuRectList) ? menuRectList[0] : menuRectList
  // #endif

  if (!menuRect) return

// 获取屏幕尺寸
  const sysInfo = uni.getSystemInfoSync()
  // 注意 windowHeight 可能受到键盘、导航栏影响，加上 windowTop 偏移更准确（特别是在 H5 中）
  const windowHeight = sysInfo.windowHeight
  const windowWidth = sysInfo.windowWidth

  const { left, right, top, bottom, width: triggerWidth, height: triggerHeight } = triggerRect
  const menuWidth = menuRect.width
  const menuHeight = menuRect.height

  let finalTop = 0
  let finalLeft = 0

  // 计算垂直位置（基于视口）
  if (props.placement.startsWith('top')) {
    finalTop = top - menuHeight - props.offset
    // 防溢出检测
    if (finalTop < 0) {
      finalTop = bottom + props.offset
    }
  } else { // bottom
    finalTop = bottom + props.offset
    // 防溢出检测：如果下方空间不够，且上方空间足够，向上翻转
    if (finalTop + menuHeight > windowHeight && top - menuHeight - props.offset > 0) {
      finalTop = top - menuHeight - props.offset
    }
  }

  // 计算水平位置
  if (props.placement.endsWith('start')) {
    finalLeft = left
  } else if (props.placement.endsWith('end')) {
    finalLeft = right - menuWidth
  } else { // center
    finalLeft = left + (triggerWidth / 2) - (menuWidth / 2)
  }

  // 水平防溢出检测
  if (finalLeft < 10) finalLeft = 10
  if (finalLeft + menuWidth > windowWidth - 10) {
    finalLeft = windowWidth - menuWidth - 10
  }

  menuStyle.value = {
    top: `${finalTop}px`,
    left: `${finalLeft}px`,
    opacity: 1,
    transform: 'scaleY(1)'
  }
}

// 关闭菜单
const closeMenu = () => {
  isShow.value = false
  menuStyle.value = {
    ...menuStyle.value,
    opacity: 0,
    transform: 'scaleY(0)'
  }
  emit('visible-change', false)
}

// 提供给子组件 (menu-item) 调用的方法
const handleItemClick = (command) => {
  emit('command', command)
  if (props.hideOnClick) {
    closeMenu()
  }
}
//
const handleMenuClick = (item,index) => {
  emit('menuClick', { value: item, index })
  console.log('menuClick', item, index,'关闭',props.hideOnClick)
  if (props.hideOnClick) {
    closeMenu()
  }
}

// 暴露给外部或子组件的方法
defineExpose({
  closeMenu,
  handleItemClick
})

</script>

<style lang="scss" scoped>
@import '@/uni.scss';

.cwg-droplist {
  display: inline-block;
  position: relative;
}

.cwg-droplist-trigger {
  display: inline-block;
  cursor: pointer;
}

.cwg-droplist-portal {
  position: fixed;
  top: 0;
  /* 解决某些浏览器下的 H5 顶部导航栏导致 fixed 参考系下移的问题 */
  /* #ifdef H5 */
  top: var(--window-top);
  /* #endif */
  left: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  visibility: hidden;

  &.is-show {
    pointer-events: auto;
    visibility: visible;
  }
}

.cwg-droplist-mask {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: transparent;
}

.cwg-droplist-menu {
  position: absolute;
  background-color: #fff;
  border: 1px solid #ebeef5;
  border-radius: px2rpx(4);
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  padding: px2rpx(10) 0;
  min-width: px2rpx(100);
  opacity: 0;
  transform: scaleY(0);
  transition: opacity 0.3s, transform 0.3s;
  box-sizing: border-box;

  /* 动画基点设置 */
  &.placement-bottom,
  &.placement-bottom-start,
  &.placement-bottom-end {
    transform-origin: top center;
  }

  &.placement-top,
  &.placement-top-start,
  &.placement-top-end {
    transform-origin: bottom center;
  }

  /* 小箭头 (可选) */
  &::before {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    border: 6px solid transparent;
  }

  &.placement-bottom::before,
  &.placement-bottom-start::before,
  &.placement-bottom-end::before {
    top: -12px;
    border-bottom-color: #ebeef5;
  }

  &.placement-bottom::before { left: 50%; transform: translateX(-50%); }
  &.placement-bottom-start::before { left: 15px; }
  &.placement-bottom-end::before { right: 15px; }

  &.placement-top::before,
  &.placement-top-start::before,
  &.placement-top-end::before {
    bottom: -12px;
    border-top-color: #ebeef5;
  }
  
  &.placement-top::before { left: 50%; transform: translateX(-50%); }
  &.placement-top-start::before { left: 15px; }
  &.placement-top-end::before { right: 15px; }
}
</style>