<template>
  <view class="ss-select-container" :class="{ open: isOpen }" @click.stop="toggleDropdown">
    <!-- 显示区域 -->
    <view class="ss-select" :class="{ disabled: disabled }">
      <text class="select-text" :class="{ placeholder: !selectedValue }">{{ displayText }}</text>
      <view class="select-arrow" :class="{ rotate: isOpen }">
        <Icon name="icon-xiangxiajiantou" size="32" :color="disabled ? '#ccc' : '#999'"/>
      </view>
    </view>
    
    <!-- 选项列表 -->
    <view class="ss-options" v-show="isOpen">
      <!-- 加载状态 -->
      <view
        v-if="finalLoading"
        class="option-item loading-item"
      >
        <text class="loading-text">加载中...</text>
      </view>
      <!-- 无选项 -->
      <view
        v-else-if="optionsList.length === 0"
        class="option-item no-options"
      >
        无选项
      </view>
      <!-- 选项列表 -->
      <view
        v-else
        v-for="(option, index) in optionsList"
        :key="index"
        class="option-item"
        :class="{ selected: option[props.mapping.value] === selectedValue }"
        @click.stop="selectOption(option)"
      >
        {{ option[props.mapping.text] }}
      </view>
    </view>
    

  </view>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import request from '@/utils/request'
import Icon from '@/components/icon/index.vue';
// Props 定义
const props = defineProps({
  // 选项数组
  options: {
    type: Array,
    default: () => []
  },
  // 字段映射
  mapping: {
    type: Object,
    default: () => ({ text: 'n', value: 'v' })
  },
  // 默认值
  modelValue: {
    type: [String, Number],
    default: ''
  },
  // 占位符
  placeholder: {
    type: String,
    default: '请选择'
  },
  // 校验配置
  validation: {
    type: Object,
    default: () => ({ enable: false, message: '' })
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false
  },
  // 是否支持搜索
  searchable: {
    type: Boolean,
    default: false
  },
  // 是否支持清空
  clearable: {
    type: Boolean,
    default: false
  },
  // 加载状态
  loading: {
    type: Boolean,
    default: false
  },
  // 宽度设置
  width: {
    type: String,
    default: '100%'
  },
  minWidth:{
    type:String,
    default:'unset'
  },
  // 对齐PC端 ss-objp：支持组件内部按 codebook 拉取下拉选项
  cb: {
    type: String,
    default: ''
  },
  url: {
    type: String,
    default: '/service?ssServ=loadObjpOpt&objectpickerdropdown1=1'
  },
  inp: {
    type: [Boolean, String],
    default: false
  },
  filter: {
    type: [Object, String],
    default: null
  },
  autoSelectFirst: {
    type: Boolean,
    default: false
  }
})

// Emits 定义
const emit = defineEmits(['update:modelValue', 'change', 'search', 'clear'])

// 响应式数据
const isOpen = ref(false)
const selectedValue = ref(props.modelValue)
const searchKeyword = ref('')
const remoteOptions = ref([])
const internalLoading = ref(false)

const parseFilterObj = () => {
  if (!props.filter) return {}
  if (typeof props.filter === 'object') return props.filter
  if (typeof props.filter === 'string') {
    try {
      const obj = JSON.parse(props.filter)
      return obj && typeof obj === 'object' ? obj : {}
    } catch (_) {
      return {}
    }
  }
  return {}
}

const normalizeResultToOptions = (respData) => {
  const raw = respData || {}
  if (Array.isArray(raw.resultList)) {
    return raw.resultList.map((it) => {
      if (it && typeof it === 'object') return it
      return { n: String(it || ''), v: String(it || '') }
    })
  }
  if (raw.result && typeof raw.result === 'object') {
    return Object.keys(raw.result).map((key) => ({
      n: raw.result[key],
      v: key
    }))
  }
  if (Array.isArray(raw.objectList)) {
    return raw.objectList.map((it) => {
      if (it && typeof it === 'object') return it
      return { n: String(it || ''), v: String(it || '') }
    })
  }
  return []
}

const maybeAutoSelectFirst = (opts) => {
  if (!props.autoSelectFirst) return
  if (!Array.isArray(opts) || opts.length === 0) return
  if (selectedValue.value !== undefined && selectedValue.value !== null && selectedValue.value !== '') return
  const first = opts[0]
  if (!first || typeof first !== 'object') return
  const value = first[props.mapping.value]
  if (value === undefined || value === null || value === '') return
  selectedValue.value = value
  emit('update:modelValue', value)
  emit('change', value, first)
}

const needRemoteData = computed(() => !!String(props.cb || '').trim())

const loadRemoteOptions = async () => {
  if (!needRemoteData.value) return

  internalLoading.value = true
  try {
    const data = {
      objectpickerparam: JSON.stringify({
        input: String(props.inp === true || props.inp === 'true'),
        codebook: String(props.cb || ''),
        ...parseFilterObj()
      }),
      objectpickertype: 1,
      objectpickersearchAll: 1
    }
    const resp = await request.post(
      props.url || '/service?ssServ=loadObjpOpt&objectpickerdropdown1=1',
      data,
      {
        loading: false,
        formData: true,
      }
    )
    const opts = normalizeResultToOptions(resp?.data)
    remoteOptions.value = opts
    maybeAutoSelectFirst(opts)
  } catch (error) {
    remoteOptions.value = []
    console.error('[SsSelect] loadRemoteOptions failed', props.cb, error)
  } finally {
    internalLoading.value = false
  }
}

// 计算属性
const optionsList = computed(() => {
  if (Array.isArray(props.options) && props.options.length > 0) return props.options
  if (needRemoteData.value) return remoteOptions.value
  return []
})
const finalLoading = computed(() => !!props.loading || internalLoading.value)

const displayText = computed(() => {
  if (!selectedValue.value) return props.placeholder
  
  const selectedOption = optionsList.value.find(
    option => option[props.mapping.value] === selectedValue.value
  )
  return selectedOption ? selectedOption[props.mapping.text] : props.placeholder
})



// 方法
const toggleDropdown = () => {
  if (props.disabled) return

  if (!isOpen.value) {
    // 关闭其他下拉框
    uni.$emit('closeAllSelects')
  }

  isOpen.value = !isOpen.value
}

const selectOption = (option) => {
  const value = option[props.mapping.value]
  selectedValue.value = value
  isOpen.value = false
  
  // 触发事件
  emit('update:modelValue', value)
  emit('change', value, option)
}

const closeDropdown = () => {
  isOpen.value = false
}

// 设置值的方法（供外部调用）
const setValue = (value) => {
  if (!value) {
    selectedValue.value = ''
    emit('update:modelValue', '')
    return true
  }
  
  const option = optionsList.value.find(
    opt => opt[props.mapping.value] === value
  )
  
  if (option) {
    selectedValue.value = value
    emit('update:modelValue', value)
    emit('change', value, option)
    return true
  }
  
  return false
}

// 监听外部值变化
watch(() => props.modelValue, (newValue) => {
  selectedValue.value = newValue
})

// 监听全局关闭事件
const handleGlobalClose = () => {
  closeDropdown()
}

onMounted(() => {
  uni.$on('closeAllSelects', handleGlobalClose)
  
  // 点击页面其他地方关闭下拉框
  uni.$on('pageClick', closeDropdown)

  loadRemoteOptions()
})

watch(
  () => [props.cb, props.url, props.filter],
  () => {
    if (!needRemoteData.value) return
    loadRemoteOptions()
  }
)

onUnmounted(() => {
  uni.$off('closeAllSelects', handleGlobalClose)
  uni.$off('pageClick', closeDropdown)
})

// 暴露方法给父组件
defineExpose({
  setValue,
  getValue: () => selectedValue.value,
  getSelectedOption: () => {
    return optionsList.value.find(
      option => option[props.mapping.value] === selectedValue.value
    )
  },
  reloadOptions: loadRemoteOptions
})
</script>

<style lang="scss" scoped>
/* ss暂用下拉框样式 */
.ss-select-container {
  position: relative;
  width: v-bind(width);
  min-width: v-bind(minWidth);
  font-size: 32rpx;

}

.ss-select {
  padding: 10rpx 0;
  border-radius: 10rpx;
  cursor: pointer;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 28rpx;
  box-sizing: border-box;

  &.disabled {
    opacity: 0.6;
    cursor: not-allowed;

    .select-text {
      color: #ccc;
    }
  }
}

.select-text {
  flex: 1;
  color: #333;

  &.placeholder {
    color: #999;
  }
}

.select-arrow {
  display: flex;
  align-items: center;
  transition: transform 0.3s ease;
  margin-left: 20rpx;

  &.rotate {
    transform: rotate(180deg);
  }
}

.ss-options {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  background-color: #393D51;
  z-index: 1000;
  color: #fff;
  border: 2rpx solid #393D51;
  box-sizing: border-box;
  border-radius: 10rpx;
  overflow: hidden;
  max-height: 600rpx;
  overflow: auto;
}

.ss-select-container.open .ss-options {
  display: block;
}

.option-item {
  padding: 20rpx 20rpx 20rpx 46rpx;
  cursor: pointer;
  position: relative;

  &::after {
    content: "";
    position: absolute;
    bottom: 0%;
    left: 50%;
    transform: translateX(-50%);
    width: 80%;
    height: 2rpx;
    background-color: #303445;
  }

  &:last-child::after,
  &:hover::after,
  &.selected::after {
    display: none;
  }

  &:hover {
    background-color: #fff;
    color: #393D51;
  }

  &.selected {
    background-color: #fff;
    color: #393D51;

    &::before {
      content: "";
      background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23393D51"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>') no-repeat center;
      position: absolute;
      width: 30rpx;
      height: 100%;
      left: 10rpx;
      top: 0;
      color: #393D51;
    }
  }

  &.no-options {
    text-align: center;
    color: #999;
    cursor: default;

    &:hover {
      background-color: #393D51;
      color: #999;
    }
  }

  &.loading-item {
    text-align: center;
    color: #999;
    cursor: default;

    &:hover {
      background-color: #393D51;
      color: #999;
    }

    .loading-text {
      animation: loading-pulse 1.5s ease-in-out infinite;
    }
  }
}

@keyframes loading-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}


</style>
