<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue';

import { useVModel } from '@vueuse/core';
import { Empty, Input, Popover, Spin } from 'ant-design-vue';

import { getExpressCompaniesOption } from '#/views/business/express/express-company/api';

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

const props = defineProps<{
  value?: string;
  disabled?: boolean;
  placeholder?: string;
}>();

const emits = defineEmits<{
  'update:value': [value: string | undefined];
}>();

const mValue = useVModel(props, 'value', emits, { passive: true });

type ExpressCompanyOption = {
  id: number;
  name: string;
  code: string;
};

const open = ref(false);
const loading = ref(false);
const searchKeyword = ref('');
const options = ref<ExpressCompanyOption[]>([]);
const searchInputRef = ref<InstanceType<typeof Input> | null>(null);

function filterExpressCompanyOptions(keyword: string, list: ExpressCompanyOption[]) {
  const q = keyword.trim().toLowerCase();
  if (!q) return list;
  return list.filter((item) => {
    const name = (item.name || '').toLowerCase();
    const code = (item.code || '').toLowerCase();
    return name.includes(q) || code.includes(q);
  });
}

const filteredOptions = computed(() =>
  filterExpressCompanyOptions(searchKeyword.value, options.value),
);

const selectedOption = computed(() =>
  options.value.find((item) => item.code === mValue.value),
);

const displayText = computed(() => {
  const item = selectedOption.value;
  if (!item) return '';
  return item.code ? `${item.name || '-'}（${item.code}）` : (item.name || '-');
});

async function loadOptions() {
  loading.value = true;
  try {
    const res = await getExpressCompaniesOption({});
    options.value = Array.isArray(res) ? res : [];
  } finally {
    loading.value = false;
  }
}

function selectOption(item: ExpressCompanyOption) {
  mValue.value = item.code;
  open.value = false;
  searchKeyword.value = '';
}

function clearSelection(e: Event) {
  e.stopPropagation();
  mValue.value = undefined;
}

function onOpenChange(next: boolean) {
  if (props.disabled) return;
  open.value = next;
  if (next) {
    searchKeyword.value = '';
    if (!options.value.length) {
      loadOptions();
    }
    nextTick(() => searchInputRef.value?.focus?.());
  }
}

watch(
  () => props.disabled,
  (disabled) => {
    if (disabled) open.value = false;
  },
);

onMounted(() => {
  loadOptions();
});
</script>

<template>
  <Popover
    :open="open"
    trigger="click"
    placement="bottomLeft"
    overlay-class-name="express-company-select-popover"
    @open-change="onOpenChange"
  >
    <template #content>
      <div class="express-panel">
        <Input
          ref="searchInputRef"
          v-model:value="searchKeyword"
          allow-clear
          placeholder="搜索公司名称或编码"
          class="express-search"
        />
        <Spin :spinning="loading">
          <div v-if="filteredOptions.length" class="express-list">
            <button
              v-for="item in filteredOptions"
              :key="item.id"
              type="button"
              class="express-item"
              :class="{ active: item.code === mValue }"
              @click="selectOption(item)"
            >
              <div class="express-meta">
                <div class="express-name">{{ item.name || '-' }}</div>
                <div class="express-sub">{{ item.code }}</div>
              </div>
            </button>
          </div>
          <Empty v-else description="无匹配快递公司" class="express-empty" />
        </Spin>
      </div>
    </template>
    <div
      class="express-trigger"
      :class="{ disabled: disabled, placeholder: !displayText }"
    >
      <Input
        :value="displayText"
        readonly
        :disabled="disabled"
        :placeholder="placeholder || '请选择快递公司'"
        class="express-trigger-input"
      >
        <template v-if="displayText && !disabled" #suffix>
          <span class="clear-btn" @click="clearSelection">×</span>
        </template>
      </Input>
    </div>
  </Popover>
</template>

<style scoped>
.express-trigger {
  width: 100%;
  cursor: pointer;
}
.express-trigger.disabled {
  cursor: not-allowed;
}
.express-trigger-input {
  pointer-events: none;
}
.express-trigger:not(.disabled) :deep(.ant-input) {
  cursor: pointer;
}
.clear-btn {
  pointer-events: auto;
  cursor: pointer;
  color: #86909c;
  font-size: 16px;
  line-height: 1;
  padding: 0 4px;
}
.express-panel {
  width: 360px;
  max-width: 80vw;
}
.express-search {
  margin-bottom: 8px;
}
.express-list {
  max-height: 280px;
  overflow-y: auto;
}
.express-item {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  border-radius: 6px;
}
.express-item:hover,
.express-item.active {
  background: #f2f3f5;
}
.express-meta {
  min-width: 0;
  flex: 1;
}
.express-name {
  font-size: 14px;
  color: #1d2129;
}
.express-sub {
  font-size: 12px;
  color: #86909c;
}
.express-empty {
  margin: 12px 0;
}
</style>

<style>
.express-company-select-popover .ant-popover-inner {
  padding: 12px;
}
</style>
