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

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

import { getDoctorOptionApi } from '#/views/system/store/api';
import { resolveAvatarUrl } from '#/views/system/store-input/utils/inputUser';

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

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

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

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

type DoctorOption = {
  id: number;
  name: string;
  avatar?: string;
  mobile?: string;
  depart_name?: string;
};

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

const isDisabled = computed(() => props.disabled || !props.storeId);

/** 按关键词过滤医生列表 */
function filterDoctorOptions(keyword: string, list: DoctorOption[]) {
  const q = keyword.trim().toLowerCase();
  if (!q) return list;
  return list.filter((item) => {
    const name = (item.name || '').toLowerCase();
    const mobile = (item.mobile || '').toLowerCase();
    const depart = (item.depart_name || '').toLowerCase();
    const idText = String(item.id);
    return (
      name.includes(q) ||
      mobile.includes(q) ||
      depart.includes(q) ||
      idText.includes(q)
    );
  });
}

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

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

/** 按诊所加载医生选项（id 为 su_id） */
async function loadOptions() {
  if (!props.storeId) {
    options.value = [];
    return;
  }
  loading.value = true;
  try {
    options.value = (await getDoctorOptionApi(props.storeId)) || [];
  } finally {
    loading.value = false;
  }
}

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

function clearSelection() {
  mValue.value = undefined;
}

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

/** 诊所变更时重载列表，并清除不在新诊所下的选中项 */
watch(
  () => props.storeId,
  async (storeId, prevStoreId) => {
    if (storeId === prevStoreId) return;
    await loadOptions();
    if (!mValue.value) return;
    const stillValid = options.value.some((item) => item.id === mValue.value);
    if (!stillValid) {
      mValue.value = undefined;
    }
  },
  { immediate: true },
);

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

<template>
  <Popover
    :open="open"
    trigger="click"
    placement="bottomLeft"
    overlay-class-name="doctor-picker-popover"
    @open-change="onOpenChange"
  >
    <template #content>
      <div class="doctor-panel">
        <Input
          ref="searchInputRef"
          v-model:value="searchKeyword"
          allow-clear
          placeholder="搜索医生姓名、手机号、科室"
          class="doctor-search"
        />
        <Spin :spinning="loading">
          <div v-if="filteredOptions.length" class="doctor-grid">
            <button
              v-for="item in filteredOptions"
              :key="item.id"
              type="button"
              class="doctor-card"
              :class="{ active: item.id === mValue }"
              @click="selectOption(item)"
            >
              <Avatar :src="resolveAvatarUrl(item.avatar)" :size="36">
                {{ (item.name || '?').charAt(0) }}
              </Avatar>
              <div class="doctor-card-name" :title="item.name">
                {{ item.name || '-' }}
              </div>
              <div v-if="item.mobile" class="doctor-card-sub">{{ item.mobile }}</div>
              <div v-if="item.depart_name" class="doctor-card-sub">
                {{ item.depart_name }}
              </div>
            </button>
          </div>
          <Empty v-else description="该诊所下无匹配医生" class="doctor-empty" />
        </Spin>
      </div>
    </template>
    <div class="doctor-trigger" :class="{ disabled: isDisabled }">
      <div v-if="selectedOption" class="doctor-selected-card">
        <Avatar :src="resolveAvatarUrl(selectedOption.avatar)" :size="36">
          {{ (selectedOption.name || '?').charAt(0) }}
        </Avatar>
        <div class="doctor-selected-info">
          <div class="doctor-selected-name">{{ selectedOption.name }}</div>
          <div class="doctor-selected-sub">
            {{ selectedOption.mobile || `su_id: ${selectedOption.id}` }}
          </div>
        </div>
        <span
          v-if="!isDisabled"
          class="doctor-clear-btn"
          title="清除"
          @click.stop="clearSelection"
        >
          ×
        </span>
      </div>
      <div v-else-if="mValue" class="doctor-selected-card">
        <div class="doctor-selected-info">
          <div class="doctor-selected-name">医生 su_id: {{ mValue }}</div>
        </div>
        <span
          v-if="!isDisabled"
          class="doctor-clear-btn"
          title="清除"
          @click.stop="clearSelection"
        >
          ×
        </span>
      </div>
      <div v-else class="doctor-trigger-placeholder">
        {{ storeId ? '请选择关联医生（可选）' : '请先选择所属诊所' }}
      </div>
    </div>
  </Popover>
</template>

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

.doctor-trigger {
  width: 100%;
}

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

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

.doctor-selected-card {
  @include theme.picker-selected-card;
}

.doctor-selected-info {
  flex: 1;
  min-width: 0;
}

.doctor-selected-name {
  font-size: 14px;
  color: #1d2129;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.doctor-selected-sub {
  font-size: 12px;
  color: #86909c;
  margin-top: 2px;
}

.doctor-clear-btn {
  @include theme.picker-clear-btn;
}

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

.dark {
  .doctor-selected-card {
    @include theme.picker-selected-card-dark-props;
  }

  .doctor-selected-name {
    @include theme.picker-text-primary-dark;
  }

  .doctor-selected-sub {
    @include theme.picker-text-secondary-dark;
  }

  .doctor-clear-btn {
    @include theme.picker-clear-dark-props;
  }

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

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

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

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

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

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

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

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

  .doctor-card-sub {
    @include theme.picker-card-sub;
  }

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

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

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

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