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

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

import { searchApiLogUsers } from '#/views/log/api-log/api';

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

export type ApiLogUserFilter = {
  id: number;
  user_type: 'admin' | 'patient' | 'doctor';
  platform_type: 0 | 1 | 2;
  name: string;
  role_label: string;
  avatar?: string;
};

type ApiLogUserOption = ApiLogUserFilter;

type UserTab = 'admin' | 'patient' | 'doctor';

const props = defineProps<{
  value?: ApiLogUserFilter;
  disabled?: boolean;
  onPlatformTypeChange?: (platformType: 0 | 1 | 2) => void;
}>();

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

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

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

const TAB_ITEMS = [
  { key: 'admin', label: '后台用户' },
  { key: 'patient', label: '患者端用户' },
  { key: 'doctor', label: '医生端用户' },
] as const;

const searchPlaceholder = computed(() => {
  if (activeTab.value === 'admin') return '搜索手机号或昵称';
  if (activeTab.value === 'patient') return '搜索用户名字';
  return '搜索名字或手机号';
});

async function fetchOptions() {
  const keyword = searchKeyword.value.trim();
  if (!keyword) {
    options.value = [];
    return;
  }

  loading.value = true;
  try {
    const result = await searchApiLogUsers({
      user_type: activeTab.value,
      keyword,
      pageSize: 24,
    });
    options.value = result?.items ?? [];
  } finally {
    loading.value = false;
  }
}

const debouncedFetch = useDebounceFn(fetchOptions, 300);

watch([searchKeyword, activeTab], () => {
  debouncedFetch();
});

function selectOption(item: ApiLogUserOption) {
  mValue.value = {
    id: item.id,
    user_type: item.user_type,
    platform_type: item.platform_type,
    name: item.name,
    role_label: item.role_label,
    avatar: item.avatar,
  };
  props.onPlatformTypeChange?.(item.platform_type);
  open.value = false;
  searchKeyword.value = '';
  options.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 = '';
    options.value = [];
    nextTick(() => searchInputRef.value?.focus?.());
  }
}

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

<template>
  <Popover
    :open="open"
    trigger="click"
    placement="bottomLeft"
    overlay-class-name="api-log-user-picker-popover"
    @open-change="onOpenChange"
  >
    <template #content>
      <div class="api-log-user-panel">
        <Tabs v-model:active-key="activeTab" size="small" class="api-log-user-tabs">
          <Tabs.TabPane
            v-for="tab in TAB_ITEMS"
            :key="tab.key"
            :tab="tab.label"
          />
        </Tabs>
        <Input
          ref="searchInputRef"
          v-model:value="searchKeyword"
          allow-clear
          :placeholder="searchPlaceholder"
          class="api-log-user-search"
        />
        <Spin :spinning="loading">
          <div v-if="options.length" class="api-log-user-grid">
            <button
              v-for="item in options"
              :key="`${item.user_type}-${item.id}`"
              type="button"
              class="api-log-user-card"
              :class="{
                active:
                  mValue?.id === item.id && mValue?.user_type === item.user_type,
              }"
              @click="selectOption(item)"
            >
              <Avatar :src="item.avatar" :size="30">
                {{ (item.name || '?').charAt(0) }}
              </Avatar>
              <div class="api-log-user-card-id">#{{ item.id }}</div>
              <div class="api-log-user-card-name" :title="item.name">
                {{ item.name }}
              </div>
              <Tag class="api-log-user-card-role" :bordered="false">
                {{ item.role_label }}
              </Tag>
            </button>
          </div>
          <Empty
            v-else
            :description="searchKeyword.trim() ? '无匹配用户' : '请输入关键词搜索'"
            class="api-log-user-empty"
          />
        </Spin>
      </div>
    </template>
    <div class="api-log-user-trigger" :class="{ disabled: disabled }">
      <div v-if="mValue" class="api-log-selected-card">
        <Avatar :src="mValue.avatar" :size="36">
          {{ (mValue.name || '?').charAt(0) }}
        </Avatar>
        <div class="api-log-selected-meta">
          <div class="api-log-selected-name">{{ mValue.name }}</div>
          <div class="api-log-selected-sub">
            #{{ mValue.id }} · {{ mValue.role_label }}
          </div>
        </div>
        <span
          v-if="!disabled"
          class="api-log-clear-btn"
          @click="clearSelection"
        >
          ×
        </span>
      </div>
      <div v-else class="api-log-trigger-placeholder">请选择操作用户</div>
    </div>
  </Popover>
</template>

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

.api-log-user-trigger {
  width: 100%;
}

.api-log-user-trigger.disabled {
  cursor: not-allowed;
  opacity: 0.65;
}

.api-log-user-trigger:not(.disabled) {
  cursor: pointer;
}

.api-log-selected-card {
  @include theme.picker-selected-card;
}

.api-log-selected-meta {
  min-width: 0;
  flex: 1;
}

.api-log-selected-name {
  font-size: 14px;
  font-weight: 500;
  color: #1d2129;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.api-log-selected-sub {
  font-size: 12px;
  color: #86909c;
  line-height: 1.4;
}

.api-log-trigger-placeholder {
  @include theme.picker-trigger-placeholder;
}

.api-log-clear-btn {
  @include theme.picker-clear-btn;
}

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

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

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

  .api-log-trigger-placeholder {
    @include theme.picker-placeholder-dark-props;
  }

  .api-log-clear-btn {
    @include theme.picker-clear-dark-props;
  }
}
</style>

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

.api-log-user-picker-popover {
  .ant-popover-inner {
    padding: 12px;
  }

  .api-log-user-panel {
    width: 540px;
    max-width: 86vw;
  }

  .api-log-user-tabs {
    margin-bottom: 8px;
  }

  .api-log-user-search {
    margin-bottom: 10px;
  }

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

  .api-log-user-card {
    @include theme.picker-card-base;
  }

  .api-log-user-card-id {
    @include theme.picker-card-sub;
  }

  .api-log-user-card-name {
    @include theme.picker-card-name;
  }

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

  .api-log-user-empty {
    margin: 16px 0;
  }
}

.dark .api-log-user-picker-popover {
  .api-log-user-card {
    @include theme.picker-card-dark-props;
  }

  .api-log-user-card-name {
    @include theme.picker-text-primary-dark;
  }

  .api-log-user-card-id {
    @include theme.picker-text-secondary-dark;
  }
}
</style>

