<template>
  <view class="multi-wrap">
    <view class="label">
      {{ name }}<text v-if="required" class="form-cell-required">*</text>
    </view>
    <view class="options" :class="hasOtherSelected ? 'with-other' : ''">
      <view
        v-for="opt in displayOptions"
        :key="opt.value"
        class="opt"
        :class="isSelected(opt.value) ? 'active' : ''"
        @click="toggle(opt.value)"
      >
        {{ opt.label }}
      </view>
    </view>
    <view v-if="hasOtherSelected" class="other">
      <input
        :disabled="disableChange"
        :value="otherText"
        class="other-input"
        placeholder="请补充其它内容"
        placeholder-class="form__placeholder"
        maxlength="50"
        @input="onOtherInput"
      />
    </view>
  </view>
</template>

<script setup>
import { computed } from 'vue';

const emits = defineEmits(['change']);
const props = defineProps({
  form: { type: Object, default: () => ({}) },
  range: { type: Array, default: () => [] },
  name: { default: '' },
  required: { type: Boolean, default: false },
  title: { default: '' },
  disableChange: { type: Boolean, default: false },
  otherList: { type: Array, default: () => ['其他'] },
});

function normalizeOptions(options) {
  if (!Array.isArray(options)) return [];
  if (!options.length) return [];
  if (typeof options[0] === 'string') return options.filter(Boolean).map((i) => ({ label: String(i), value: String(i) }));
  return options
    .map((i) => {
      const label = i?.label ?? i?.name ?? i?.text ?? i?.title ?? '';
      const value = i?.value ?? i?.id ?? i?.key ?? label;
      if (!label && (value === undefined || value === null || value === '')) return null;
      return { label: String(label || value), value: String(value) };
    })
    .filter(Boolean);
}

const displayOptions = computed(() => normalizeOptions(props.range));
const valueList = computed(() => (Array.isArray(props.form?.[props.title]) ? props.form[props.title] : []));

const otherValue = computed(() => {
  const selected = valueList.value.map(String);
  const rangeValues = new Set(displayOptions.value.map((i) => String(i.value)));
  const extra = selected.filter((i) => !rangeValues.has(String(i)));
  return extra[0] || '';
});

const hasOtherSelected = computed(() => {
  const selected = valueList.value.map(String);
  return selected.some((v) => props.otherList.map(String).includes(v));
});

const otherText = computed(() => otherValue.value);

function isSelected(v) {
  return valueList.value.map(String).includes(String(v));
}

function emitValue(next) {
  emits('change', { title: props.title, value: next });
}

function toggle(v) {
  if (props.disableChange) return;
  const str = String(v);
  let next = valueList.value.map(String);

  if (next.includes(str)) {
    next = next.filter((i) => i !== str);
  } else {
    next.push(str);
  }

  const isOther = props.otherList.map(String).includes(str);
  if (!isOther) {
    // 如果取消了 other 的选择，清理 other 文本
    const stillHasOther = next.some((i) => props.otherList.map(String).includes(i));
    if (!stillHasOther) {
      const rangeValues = new Set(displayOptions.value.map((i) => String(i.value)));
      next = next.filter((i) => rangeValues.has(i));
    }
  }
  emitValue(next);
}

function onOtherInput(e) {
  const text = String(e?.detail?.value || '').trim();
  const rangeValues = new Set(displayOptions.value.map((i) => String(i.value)));
  let next = valueList.value.map(String).filter((i) => rangeValues.has(i));
  const hasOther = valueList.value.map(String).some((i) => props.otherList.map(String).includes(i));
  if (hasOther) {
    next.push(...props.otherList.map(String).slice(0, 1));
    if (text) next.push(text);
  }
  emitValue(next);
}
</script>

<style lang="scss" scoped>
@import '../cell-style.css';

.multi-wrap {
  padding: 24rpx 30rpx;
  border-bottom: 1px solid #eee;
}

.label {
  font-size: 30rpx;
  line-height: 42rpx;
}

.options {
  margin-top: 18rpx;
  display: flex;
  flex-wrap: wrap;
  gap: 18rpx;
}

.opt {
  min-width: 150rpx;
  padding: 12rpx 20rpx;
  border: 1px solid #ddd;
  border-radius: 8rpx;
  font-size: 28rpx;
  text-align: center;
  color: #333;
  background: #fff;
}

.opt.active {
  background: rgba(93, 138, 255, 0.12);
  border-color: rgba(93, 138, 255, 0.35);
  color: #5d8aff;
}

.other {
  margin-top: 18rpx;
}

.other-input {
  width: 100%;
  font-size: 30rpx;
  padding: 18rpx 20rpx;
  border: 1px solid #eee;
  border-radius: 8rpx;
  box-sizing: border-box;
}
</style>
