<script setup lang="ts">
import type { AgentOption } from '../types';

import { computed, nextTick, ref, watch } from 'vue';

import { Search } from '@element-plus/icons-vue';
import {
  ElButton,
  ElCheckbox,
  ElDialog,
  ElEmpty,
  ElInput,
  ElScrollbar,
} from 'element-plus';

const props = withDefaults(
  defineProps<{
    boundSkillIds?: Array<number | string>;
    error?: string;
    loading?: boolean;
    modelValue: boolean;
    options: AgentOption[];
  }>(),
  {
    boundSkillIds: () => [],
    error: '',
    loading: false,
  },
);

const emit = defineEmits<{
  add: [options: AgentOption[]];
  retry: [];
  'update:modelValue': [value: boolean];
}>();

const keyword = ref('');
const selectedIds = ref<string[]>([]);
const searchInput = ref<InstanceType<typeof ElInput>>();

const boundIds = computed(() => new Set(props.boundSkillIds.map(String)));
const remainingCount = computed(() => Math.max(0, 20 - boundIds.value.size));
const normalizedKeyword = computed(() =>
  keyword.value.trim().toLocaleLowerCase(),
);
const filteredOptions = computed(() => {
  const query = normalizedKeyword.value;
  if (!query) return props.options;
  const terms = query.split(/\s+/).filter(Boolean);
  return props.options.filter((option) => {
    const raw = option.raw || {};
    const searchableText = [option.label, raw.description]
      .map((value) => String(value || '').toLocaleLowerCase())
      .join(' ');
    return terms.every((term) => searchableText.includes(term));
  });
});
const selectedOptions = computed(() => {
  const ids = new Set(selectedIds.value);
  return props.options.filter((option) => ids.has(String(option.value)));
});

watch(
  () => props.modelValue,
  async (open) => {
    if (!open) return;
    keyword.value = '';
    selectedIds.value = [];
    await nextTick();
    searchInput.value?.focus();
  },
);

function scopeLabel(scope: unknown) {
  const normalized = String(scope || '').toUpperCase();
  if (normalized === 'ALL' || normalized === 'PUBLIC') return '全部';
  if (normalized === 'DEPARTMENT' || normalized === 'DEPT') return '部门';
  return '个人';
}

function resourceSummary(option: AgentOption) {
  const raw = option.raw || {};
  const textCount = Math.max(0, Number(raw.textResourceCount) || 0);
  const binaryCount = Math.max(0, Number(raw.binaryResourceCount) || 0);
  const toolCount = Math.max(0, Number(raw.toolCount) || 0);
  const resources = textCount + binaryCount;
  return `${toolCount} 个工具 · ${resources} 个资源`;
}

function isOptionDisabled(option: AgentOption) {
  const id = String(option.value);
  if (boundIds.value.has(id)) return true;
  return (
    !selectedIds.value.includes(id) &&
    selectedIds.value.length >= remainingCount.value
  );
}

function toggleOption(option: AgentOption) {
  if (isOptionDisabled(option)) return;
  const id = String(option.value);
  selectedIds.value = selectedIds.value.includes(id)
    ? selectedIds.value.filter((selectedId) => selectedId !== id)
    : [...selectedIds.value, id];
}

function confirmSelection() {
  if (selectedOptions.value.length === 0) return;
  emit('add', selectedOptions.value);
  emit('update:modelValue', false);
}
</script>

<template>
  <ElDialog
    class="agent-skill-selector"
    :close-on-click-modal="false"
    :model-value="modelValue"
    title="添加技能"
    @update:model-value="emit('update:modelValue', $event)"
  >
    <div class="agent-skill-selector__toolbar">
      <ElInput
        ref="searchInput"
        v-model="keyword"
        clearable
        :prefix-icon="Search"
        placeholder="搜索技能名称或描述"
        aria-label="搜索技能"
      />
      <span class="agent-skill-selector__limit">
        已绑定 {{ boundIds.size }} / 20
      </span>
    </div>

    <div v-loading="loading" class="agent-skill-selector__content">
      <div v-if="error && !loading" class="agent-skill-selector__state">
        <ElEmpty description="技能列表加载失败">
          <ElButton type="primary" @click="emit('retry')">重新加载</ElButton>
        </ElEmpty>
      </div>
      <div
        v-else-if="!loading && filteredOptions.length === 0"
        class="agent-skill-selector__state"
      >
        <ElEmpty :description="keyword ? '未找到匹配技能' : '暂无可用技能'" />
      </div>
      <ElScrollbar v-else class="agent-skill-selector__scrollbar">
        <div
          class="agent-skill-selector__list"
          role="listbox"
          aria-label="可用技能"
        >
          <div
            v-for="option in filteredOptions"
            :key="option.value"
            class="agent-skill-selector__item"
            :class="{
              'is-bound': boundIds.has(String(option.value)),
              'is-disabled': isOptionDisabled(option),
              'is-selected': selectedIds.includes(String(option.value)),
            }"
            role="option"
            :aria-disabled="isOptionDisabled(option)"
            :aria-selected="selectedIds.includes(String(option.value))"
            :tabindex="isOptionDisabled(option) ? -1 : 0"
            @click="toggleOption(option)"
            @keydown.enter.prevent="toggleOption(option)"
            @keydown.space.prevent="toggleOption(option)"
          >
            <ElCheckbox
              :aria-label="`选择 ${option.label}`"
              :disabled="isOptionDisabled(option)"
              :model-value="selectedIds.includes(String(option.value))"
              @change="toggleOption(option)"
              @click.stop
            />
            <span class="agent-skill-selector__item-body">
              <span class="agent-skill-selector__item-heading">
                <span class="agent-skill-selector__name">{{
                  option.label
                }}</span>
                <span class="agent-skill-selector__scope">
                  {{ scopeLabel(option.raw?.visibilityScope) }}
                </span>
                <span
                  v-if="boundIds.has(String(option.value))"
                  class="agent-skill-selector__bound"
                >
                  已绑定
                </span>
              </span>
              <span class="agent-skill-selector__description">
                {{ option.raw?.description || '暂无描述' }}
              </span>
              <span class="agent-skill-selector__meta">
                {{ resourceSummary(option) }}
                <template v-if="Number(option.raw?.binaryResourceCount) > 0">
                  · 含非文本资源
                </template>
              </span>
            </span>
          </div>
        </div>
      </ElScrollbar>
    </div>

    <template #footer>
      <div class="agent-skill-selector__footer">
        <span>
          <template v-if="remainingCount === 0">已达到绑定上限</template>
          <template v-else>已选择 {{ selectedIds.length }} 个</template>
        </span>
        <div class="agent-skill-selector__actions">
          <ElButton @click="emit('update:modelValue', false)">取消</ElButton>
          <ElButton
            type="primary"
            :disabled="selectedIds.length === 0"
            @click="confirmSelection"
          >
            添加
          </ElButton>
        </div>
      </div>
    </template>
  </ElDialog>
</template>

<style scoped>
:global(.agent-skill-selector) {
  width: min(760px, calc(100vw - var(--space-8))) !important;
  border-radius: var(--radius-float);
}

:global(.agent-skill-selector .el-dialog__body) {
  padding: 0 var(--space-6);
}

.agent-skill-selector__toolbar,
.agent-skill-selector__footer,
.agent-skill-selector__item-heading {
  display: flex;
  align-items: center;
}

.agent-skill-selector__toolbar {
  gap: var(--space-4);
  padding-bottom: var(--space-4);
}

.agent-skill-selector__toolbar :deep(.el-input) {
  flex: 1;
}

.agent-skill-selector__limit,
.agent-skill-selector__meta,
.agent-skill-selector__footer {
  font-size: 12px;
  color: hsl(var(--text-muted));
}

.agent-skill-selector__content {
  min-height: 360px;
  border-top: 1px solid hsl(var(--line-subtle));
  border-bottom: 1px solid hsl(var(--line-subtle));
}

.agent-skill-selector__scrollbar {
  height: min(52vh, 480px);
}

.agent-skill-selector__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) 0;
}

.agent-skill-selector__item {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3);
  cursor: pointer;
  background: hsl(var(--surface-panel));
  border: 1px solid transparent;
  border-radius: var(--radius-toolbar);
  transition:
    background-color var(--motion-duration-base) var(--motion-ease-standard),
    border-color var(--motion-duration-base) var(--motion-ease-standard);
}

.agent-skill-selector__item:hover {
  background: hsl(var(--surface-subtle));
}

.agent-skill-selector__item:active {
  background: hsl(var(--surface-contrast-soft));
}

.agent-skill-selector__item:focus-within {
  border-color: hsl(var(--primary));
}

.agent-skill-selector__item.is-selected {
  background: hsl(var(--nav-item-active));
  border-color: hsl(var(--primary) / 0.28);
}

.agent-skill-selector__item.is-bound,
.agent-skill-selector__item.is-disabled {
  cursor: default;
  opacity: 0.72;
}

.agent-skill-selector__item-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
}

.agent-skill-selector__item-heading {
  gap: var(--space-2);
}

.agent-skill-selector__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 14px;
  font-weight: 650;
  color: hsl(var(--text-strong));
  white-space: nowrap;
}

.agent-skill-selector__scope,
.agent-skill-selector__bound {
  flex: 0 0 auto;
  padding: 1px 7px;
  font-size: 11px;
  line-height: 18px;
  border-radius: var(--radius-pill);
}

.agent-skill-selector__scope {
  color: hsl(var(--nav-item-active-foreground));
  background: hsl(var(--nav-item-active));
}

.agent-skill-selector__bound {
  color: hsl(var(--text-muted));
  background: hsl(var(--surface-contrast-soft));
}

.agent-skill-selector__description {
  margin-top: var(--space-1);
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 13px;
  line-height: 20px;
  color: var(--el-text-color-regular);
  white-space: nowrap;
}

.agent-skill-selector__meta {
  margin-top: var(--space-1);
}

.agent-skill-selector__state {
  display: grid;
  min-height: 360px;
  place-items: center;
}

.agent-skill-selector__footer {
  justify-content: space-between;
  min-height: 40px;
}

.agent-skill-selector__actions {
  display: flex;
  gap: var(--space-2);
}

@media (max-width: 820px) {
  :global(.agent-skill-selector) {
    width: calc(100vw - var(--space-4)) !important;
    margin-top: var(--space-4) !important;
  }

  .agent-skill-selector__toolbar {
    align-items: stretch;
    flex-direction: column;
  }
}
</style>
