<template>
  <ElPopover
    placement="bottom-start"
    :width="420"
    trigger="click"
    :teleported="false"
    popper-class="product-type-filter-popper"
  >
    <div class="ptf-panel">
      <div v-for="group in options" :key="String(group.value)" class="ptf-group">
        <div class="ptf-group-header">
          <div class="ptf-group-title">{{ group.label }}</div>
          <div class="ptf-group-actions">
            <ElCheckbox
              v-if="isMulti"
              :model-value="isGroupAllChecked(group)"
              :indeterminate="isGroupIndeterminate(group)"
              @change="toggleGroupAll(group)"
            />
            <template v-if="isMulti">
              <span class="ptf-select-all" @click="toggleGroupAll(group)">全选</span>
            </template>

            <template v-else>
              <ElCheckbox
                :model-value="isGroupAllChecked(group)"
                :indeterminate="isGroupIndeterminate(group)"
                @change="toggleGroupAll(group)"
              />
              <span class="ptf-select-all" @click="toggleGroupAll(group)">全选</span>
            </template>
          </div>
        </div>

        <div class="ptf-items">
          <div
            v-for="item in group.children"
            :key="String(item.value)"
            class="ptf-item"
            :class="{ active: isSelected(item.value) }"
            @click="handleItemClick(item.value)"
          >
            <ElCheckbox
              :model-value="isSelected(item.value)"
              @change="() => handleItemClick(item.value)"
              @click.stop
            />
            <span class="ptf-item-label">{{ item.label }}</span>
          </div>
        </div>
      </div>
    </div>

    <template #reference>
      <ElInput
        class="ptf-trigger"
        :model-value="displayText"
        :placeholder="placeholder"
        readonly
        clearable
        :style="{ width: width }"
        @clear="clearValue"
      >
        <template #suffix>
          <el-icon class="ptf-arrow"><ArrowDown /></el-icon>
        </template>
      </ElInput>
    </template>
  </ElPopover>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { ArrowDown } from '@element-plus/icons-vue'
import type { ProductTypeGroup, ProductTypeValue } from './productTypeFilterTypes'

type Model = ProductTypeValue | ProductTypeValue[] | null | undefined

const props = withDefaults(
  defineProps<{
    modelValue: Model
    options: ProductTypeGroup[]
    multiple?: boolean
    placeholder?: string
    width?: string
  }>(),
  {
    multiple: false,
    placeholder: '请选择',
  },
)

const emit = defineEmits<{
  (e: 'update:modelValue', v: Model): void
}>()

const isMulti = computed(() => props.multiple || Array.isArray(props.modelValue))

const valueArray = computed<ProductTypeValue[]>(() => {
  if (!isMulti.value) return []
  const v = props.modelValue
  return Array.isArray(v) ? v : v == null ? [] : [v]
})

const labelMap = computed(() => {
  const map = new Map<ProductTypeValue, string>()
  for (const g of props.options) {
    map.set(g.value, g.label)
    for (const c of g.children) {
      map.set(c.value, c.label)
    }
  }
  return map
})

const displayText = computed(() => {
  const v = props.modelValue
  if (isMulti.value) {
    const arr = valueArray.value
    if (!arr.length) return ''
    return arr.map((x) => labelMap.value.get(x) ?? String(x)).join('，')
  }
  if (v == null || Array.isArray(v)) return ''
  return labelMap.value.get(v) ?? String(v)
})

const isSelected = (v: ProductTypeValue) => {
  if (isMulti.value) return valueArray.value.includes(v)
  const cur = props.modelValue
  return !Array.isArray(cur) && cur != null && cur === v
}

const selectSingle = (v: ProductTypeValue) => {
  emit('update:modelValue', v)
}

const handleItemClick = (v: ProductTypeValue) => {
  if (!isMulti.value) {
    selectSingle(v)
    return
  }
  const next = new Set(valueArray.value)
  if (next.has(v)) next.delete(v)
  else next.add(v)
  emit('update:modelValue', Array.from(next))
}

const isGroupAllChecked = (group: ProductTypeGroup) => {
  if (!isMulti.value) return false
  const set = new Set(valueArray.value)
  return group.children.length > 0 && group.children.every((c) => set.has(c.value))
}

const isGroupIndeterminate = (group: ProductTypeGroup) => {
  if (!isMulti.value) return false
  const set = new Set(valueArray.value)
  const checkedCount = group.children.filter((c) => set.has(c.value)).length
  return checkedCount > 0 && checkedCount < group.children.length
}

const toggleGroupAll = (group: ProductTypeGroup) => {
  if (!group.children?.length) return
  const nextAll = group.children.map((c) => c.value)
  if (!isMulti.value) {
    emit('update:modelValue', nextAll)
    return
  }
  const set = new Set(valueArray.value)
  const allChecked = isGroupAllChecked(group)
  for (const c of group.children) {
    if (allChecked) set.delete(c.value)
    else set.add(c.value)
  }
  emit('update:modelValue', Array.from(set))
}

const clearValue = () => {
  emit('update:modelValue', isMulti.value ? [] : null)
}
</script>

<style scoped lang="scss">
.ptf-panel {
  padding: 6px 0;
  max-height: 360px;
  overflow: auto;
  :deep(.el-checkbox) {
    margin-right: 2px !important;
  }
}

.ptf-group {
  border: 1px solid #e5e6eb;
  border-top: 0;
}
.ptf-group:first-child {
  border-top: 1px solid #e5e6eb;
}

.ptf-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  background: #fff;
}

.ptf-group-title {
  font-size: 14px;
  font-weight: 600;
  color: #1f2329;
}

.ptf-group-actions {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: #1f2329;
  user-select: none;
}

.ptf-select-all {
  cursor: pointer;
  font-size: 13px;
}

.ptf-items {
  background: #f5f6f7;
  padding: 6px 0;
}

.ptf-item {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  padding: 0px 12px;
  box-sizing: border-box;
  cursor: pointer;
  
}

.ptf-item-label {
  font-size: 14px;
  color: #1f2329;
}

.ptf-item.active .ptf-item-label {
  color: #409eff;
}

.ptf-trigger :deep(.el-input__wrapper) {
  cursor: pointer;
}

.ptf-arrow {
  color: #909399;
}
</style>

<style lang="scss">
.product-type-filter-popper {
  padding: 0 !important;
}
</style>

