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

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

import PromoterInfoCard from '#/components/promoter/PromoterInfoCard.vue';
import { getPromoterOptions } from '#/views/system/store-input/api';
import { resolveAvatarUrl } from '#/views/system/store-input/utils/inputUser';

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

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

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

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

type PromoterOption = {
  id: number;
  nick_name: string;
  avatar: string;
  code: string;
  phone: string;
  role_id: number;
  role_name: string;
};

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

function filterPromoterOptions(keyword: string, list: PromoterOption[]) {
  const q = keyword.trim().toLowerCase();
  if (!q) return list;
  return list.filter((item) => {
    const name = (item.nick_name || '').toLowerCase();
    const code = (item.code || '').toLowerCase();
    const phone = (item.phone || '').toLowerCase();
    const role = (item.role_name || '').toLowerCase();
    return (
      name.includes(q) ||
      code.includes(q) ||
      phone.includes(q) ||
      role.includes(q)
    );
  });
}

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

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

async function loadOptions() {
  loading.value = true;
  try {
    options.value = (await getPromoterOptions()) || [];
    if (options.value.length === 1 && !mValue.value) {
      mValue.value = options.value[0].code;
    }
  } finally {
    loading.value = false;
  }
}

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

function clearSelection() {
  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="promoter-picker-popover"
    @open-change="onOpenChange"
  >
    <template #content>
      <div class="promoter-panel">
        <Input
          ref="searchInputRef"
          v-model:value="searchKeyword"
          allow-clear
          placeholder="搜索业务员姓名、业务码、手机号"
          class="promoter-search"
        />
        <Spin :spinning="loading">
          <div v-if="filteredOptions.length" class="promoter-grid">
            <button
              v-for="item in filteredOptions"
              :key="item.id"
              type="button"
              class="promoter-card"
              :class="{ active: item.code === mValue }"
              @click="selectOption(item)"
            >
              <Avatar :src="resolveAvatarUrl(item.avatar)" :size="30">
                {{ (item.nick_name || '?').charAt(0) }}
              </Avatar>
              <div class="promoter-card-name" :title="item.nick_name">
                {{ item.nick_name || '-' }}
              </div>
              <div class="promoter-card-sub">{{ item.code }}</div>
              <div v-if="item.phone" class="promoter-card-phone">
                <SensitiveText :record="item" field="phone" :show-eye="false" />
              </div>
              <Tag class="promoter-card-role" :bordered="false">
                {{ item.role_name || '业务员' }}
              </Tag>
            </button>
          </div>
          <Empty v-else description="无匹配业务员" class="promoter-empty" />
        </Spin>
      </div>
    </template>
    <div class="promoter-trigger" :class="{ disabled: disabled }">
      <PromoterInfoCard
        v-if="selectedOption"
        :admin="selectedOption"
        size="trigger"
        :show-clear="!disabled"
        :disabled="disabled"
        :clickable="false"
        @clear="clearSelection"
      />
      <div v-else class="promoter-trigger-placeholder">请选择业务员</div>
    </div>
  </Popover>
</template>

<style scoped lang="scss">
@use './picker-card-theme.scss' as theme;

.promoter-trigger {
  width: 100%;
}

.promoter-trigger.disabled {
  cursor: not-allowed;
  opacity: 0.65;
}

.promoter-trigger:not(.disabled) {
  cursor: pointer;
}

.promoter-trigger-placeholder {
  @include theme.picker-trigger-placeholder;
}

.dark {
  .promoter-trigger-placeholder {
    @include theme.picker-placeholder-dark-props;
  }
}
</style>

<style lang="scss">
@use './picker-card-theme.scss' as theme;

.promoter-picker-popover {
  .ant-popover-inner {
    padding: 12px;
  }

  .promoter-panel {
    width: 540px;
    max-width: 86vw;
  }

  .promoter-search {
    margin-bottom: 10px;
  }

  .promoter-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
    gap: 8px;
    max-height: 300px;
    overflow-y: auto;
    padding: 2px;
  }

  .promoter-card {
    @include theme.picker-card-base;
  }

  .promoter-card-name {
    @include theme.picker-card-name;
  }

  .promoter-card-sub,
  .promoter-card-phone {
    @include theme.picker-card-sub;
  }

  .promoter-card-role {
    margin: 0;
    font-size: 11px;
    line-height: 18px;
    padding: 0 6px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .promoter-empty {
    margin: 16px 0;
  }
}

.dark .promoter-picker-popover {
  .promoter-card {
    @include theme.picker-card-dark-props;
  }

  .promoter-card-name {
    @include theme.picker-text-primary-dark;
  }

  .promoter-card-sub,
  .promoter-card-phone {
    @include theme.picker-text-secondary-dark;
  }
}
</style>
