<script setup lang="ts">
/**
 * 通用 Tag 选择器（带头像）
 *
 * - 基于 antd Select，multiple 模式默认开启，单选传 multiple=false
 * - 已选项以 Tag 形式展示头像+名字：
 *   - 有 avatar 用图片头像
 *   - 无 avatar 用文本头像（取 label 首字符）
 * - 下拉选项同样展示头像+名字
 * - 选项数据：options: { value, label, avatar? }[]
 */
import { computed } from 'vue';

import { useVModel } from '@vueuse/core';
import { Avatar, Select, Tag } from 'ant-design-vue';

defineOptions({
  name: 'UserTagSelect',
  inheritAttrs: false,
});

/** 单个选项结构 */
export interface UserTagOption {
  value: string | number;
  label: string;
  avatar?: string;
}

const props = withDefaults(
  defineProps<{
    /** 已选值数组（多选）或单值（单选时仍用数组包装） */
    modelValue?: (string | number)[];
    /** 选项列表 */
    options: UserTagOption[];
    /** 是否多选，默认 true */
    multiple?: boolean;
    /** 最大选择数，超出截断 */
    maxCount?: number;
    placeholder?: string;
    allowClear?: boolean;
    showSearch?: boolean;
    disabled?: boolean;
  }>(),
  {
    modelValue: () => [],
    multiple: true,
    maxCount: 99,
    placeholder: '请选择',
    allowClear: true,
    showSearch: true,
    disabled: false,
  },
);

const emit = defineEmits<{
  'update:modelValue': [v: (string | number)[]];
}>();

// 双向绑定：useVModel 自动处理 modelValue 的读写
const innerValue = useVModel(props, 'modelValue', emit, {
  defaultValue: [] as (string | number)[],
  passive: true,
});

/** 用于 Select 的 mode，单选时不传 mode */
const selectMode = computed(() => (props.multiple ? 'multiple' : undefined));

/** 按 value 索引选项，方便 tagRender/option 插槽快速查头像与名字 */
const optionMap = computed(() => {
  const map = new Map<string | number, UserTagOption>();
  for (const opt of props.options) {
    map.set(opt.value, opt);
  }
  return map;
});

/** 取某 value 对应的展示名 */
function labelOf(value: string | number) {
  return optionMap.value.get(value)?.label || String(value);
}

/** 取某 value 对应的头像 */
function avatarOf(value: string | number) {
  return optionMap.value.get(value)?.avatar;
}

/** 取首字符（文本头像） */
function firstChar(label?: string) {
  return (label || '?').trim().charAt(0) || '?';
}

/** 选项过滤：按 label 包含输入关键字 */
function filterOption(input: string, option: any) {
  const v = String(option?.label || '').toLowerCase();
  return v.includes((input || '').toLowerCase());
}

/**
 * change 处理：
 * - 单选：把单值包成数组
 * - 多选：超 maxCount 截断
 */
function onChange(v: any) {
  if (!props.multiple) {
    innerValue.value = v == null ? [] : [v];
    return;
  }
  if (Array.isArray(v) && v.length > props.maxCount) {
    v = v.slice(0, props.maxCount);
  }
  innerValue.value = v;
}
</script>

<template>
  <Select
    :value="innerValue as any"
    :mode="selectMode"
    :options="options"
    :placeholder="placeholder"
    :allow-clear="allowClear"
    :show-search="showSearch"
    :filter-option="filterOption"
    :disabled="disabled"
    :max-tag-count="10"
    option-filter-prop="label"
    style="width: 100%"
    @change="onChange"
  >
    <!-- 多选已选项展示头像+名字 -->
    <template v-if="multiple" #tagRender="{ value, closable, onClose }">
      <Tag :closable="closable" @close="onClose" class="user-tag-chip">
        <Avatar :size="16" :src="avatarOf(value)">
          {{ firstChar(labelOf(value)) }}
        </Avatar>
        <span class="user-tag-name">{{ labelOf(value) }}</span>
      </Tag>
    </template>

    <!-- 下拉选项展示头像+名字 -->
    <template #option="{ label, avatar }">
      <div class="user-tag-option">
        <Avatar :size="20" :src="avatar">{{ firstChar(label) }}</Avatar>
        <span>{{ label }}</span>
      </div>
    </template>
  </Select>
</template>

<style scoped>
.user-tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
}

.user-tag-name {
  max-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-tag-option {
  display: flex;
  align-items: center;
  gap: 8px;
}
</style>
