<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 { matchExpressByTrackingNo } from '#/utils/matchExpressByTrackingNo';
import { getExpressCompaniesOption } from '#/views/business/express/express-company/api';

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

const props = defineProps<{
  disabled?: boolean;
  placeholder?: string;
  /** 运单号：变化时按前缀自动匹配快递公司（用户手动改选后不再覆盖） */
  trackingNo?: string;
  value?: string;
}>();

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

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

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

const open = ref(false);
const loading = ref(false);
const searchKeyword = ref('');
const options = ref<ExpressCompanyOption[]>([]);
const searchInputRef = ref<InstanceType<typeof Input> | null>(null);
/** 用户是否已手动选择/清空；为 true 时不再按单号自动覆盖 */
const userPicked = ref(false);

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 || '-';
});

/**
 * 根据 trackingNo 自动选中快递公司
 * 规则：尚未手动改选，或当前选中仍与规则结果一致时才覆盖
 */
function tryAutoMatchByTrackingNo() {
  if (options.value.length === 0) return;
  const matched = matchExpressByTrackingNo(props.trackingNo, options.value);
  if (!matched?.code) return;
  const matchedCode = matched.code;
  if (userPicked.value && mValue.value && mValue.value !== matchedCode) {
    // 用户已选其他公司，不覆盖
    return;
  }
  if (mValue.value === matchedCode) return;
  mValue.value = matchedCode;
}

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

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

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

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

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

watch(
  () => props.trackingNo,
  () => {
    // 单号变化时允许再自动匹配（除非用户已改选为不一致公司）
    tryAutoMatchByTrackingNo();
  },
);

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

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

<style scoped>
.express-trigger {
  width: 100%;
  /* min-width: fit-content; */
  min-width: 250px;
  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: hsl(var(--muted-foreground));
  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;
  color: hsl(var(--foreground));
}
.express-item:hover,
.express-item.active {
  background: hsl(var(--accent));
}
.express-meta {
  min-width: 0;
  flex: 1;
}
.express-name {
  font-size: 14px;
  color: hsl(var(--foreground));
}
.express-sub {
  font-size: 12px;
  color: hsl(var(--muted-foreground));
}
.express-empty {
  margin: 12px 0;
}
</style>

<style>
.express-company-select-popover .ant-popover-inner {
  padding: 12px;
  background: hsl(var(--card));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border));
}
</style>
