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

import {ArrowRight, Check, Close, Collection, Plus,} from '@element-plus/icons-vue';
import {ElPopover} from 'element-plus';

interface KnowledgeOption {
  label: string;
  value: string;
}

interface KnowledgeView {
  id: string;
  title: string;
}

const props = withDefaults(
  defineProps<{
    disabled?: boolean;
    extraKnowledgeIds?: string[];
    knowledgeOptions?: KnowledgeOption[];
    loading?: boolean;
    selectedKnowledges?: KnowledgeView[];
    showTrigger?: boolean;
  }>(),
  {
    disabled: false,
    extraKnowledgeIds: () => [],
    knowledgeOptions: () => [],
    loading: false,
    selectedKnowledges: () => [],
    showTrigger: true,
  },
);

const emit = defineEmits<{
  'update:extraKnowledgeIds': [value: string[]];
}>();

const MAX_EXTRA_KNOWLEDGE_COUNT = 3;
const rootOpen = ref(false);
const knowledgeOpen = ref(false);
const selectedIdSet = computed(
  () => new Set(props.extraKnowledgeIds.map(String)),
);

function setKnowledgeOpen(open: boolean) {
  if (props.disabled) {
    return;
  }
  knowledgeOpen.value = open;
}

watch(rootOpen, (open) => {
  if (!open) {
    knowledgeOpen.value = false;
  }
});

function updateKnowledgeIds(value: string[]) {
  emit('update:extraKnowledgeIds', value);
}

function isSelected(id: string) {
  return selectedIdSet.value.has(String(id));
}

function isKnowledgeDisabled(id: string) {
  return (
    props.disabled ||
    props.loading ||
    (props.extraKnowledgeIds.length >= MAX_EXTRA_KNOWLEDGE_COUNT &&
      !isSelected(id))
  );
}

function toggleKnowledge(id: string) {
  const normalizedId = String(id);
  const nextIds = props.extraKnowledgeIds.map(String);
  const currentIndex = nextIds.indexOf(normalizedId);
  if (currentIndex !== -1) {
    nextIds.splice(currentIndex, 1);
    updateKnowledgeIds(nextIds);
    return;
  }
  if (nextIds.length >= MAX_EXTRA_KNOWLEDGE_COUNT) {
    return;
  }
  nextIds.push(normalizedId);
  updateKnowledgeIds(nextIds);
}

function removeKnowledge(id: string) {
  updateKnowledgeIds(
    props.extraKnowledgeIds.filter((item) => String(item) !== String(id)),
  );
}
</script>

<template>
  <div
    v-if="showTrigger || selectedKnowledges.length > 0"
    class="chat-capability"
  >
    <div v-if="selectedKnowledges.length > 0" class="chat-capability__chips">
      <span
        v-for="knowledge in selectedKnowledges"
        :key="knowledge.id"
        class="chat-capability__chip"
      >
        <Collection class="chat-capability__chip-icon" />
        <span class="chat-capability__chip-label">{{ knowledge.title }}</span>
        <button
          type="button"
          class="chat-capability__chip-remove"
          aria-label="移除知识库"
          :disabled="disabled"
          @click="removeKnowledge(knowledge.id)"
        >
          <Close />
        </button>
      </span>
    </div>

    <ElPopover
      v-if="showTrigger"
      v-model:visible="rootOpen"
      placement="top-start"
      :show-arrow="false"
      :width="120"
      :offset="8"
      popper-class="chat-capability-popper"
      trigger="click"
    >
      <template #reference>
        <button
          type="button"
          class="chat-capability__trigger"
          :class="{ 'is-open': rootOpen }"
          :disabled="disabled"
          aria-label="添加能力"
          title="添加能力"
        >
          <Plus />
        </button>
      </template>

      <div class="chat-capability__menu" @mouseleave="setKnowledgeOpen(false)">
        <button
          type="button"
          class="chat-capability__menu-item"
          :class="{ 'is-open': knowledgeOpen }"
          :disabled="disabled"
          @click="setKnowledgeOpen(true)"
          @focus="setKnowledgeOpen(true)"
          @mouseenter="setKnowledgeOpen(true)"
        >
          <Collection class="chat-capability__menu-icon" />
          <span>知识库</span>
          <ArrowRight class="chat-capability__menu-arrow" />
        </button>

        <div
          v-if="knowledgeOpen"
          class="chat-capability__knowledge-panel"
          @mouseenter="setKnowledgeOpen(true)"
          @mouseleave="setKnowledgeOpen(false)"
        >
          <div class="chat-capability__knowledge-head">
            <span>选择知识库</span>
            <span>最多 3 个</span>
          </div>
          <div
            v-if="knowledgeOptions.length > 0"
            class="chat-capability__knowledge-list"
          >
            <button
              v-for="item in knowledgeOptions"
              :key="item.value"
              type="button"
              class="chat-capability__knowledge-item"
              :class="{
                'is-active': isSelected(item.value),
                'is-disabled': isKnowledgeDisabled(item.value),
              }"
              :disabled="isKnowledgeDisabled(item.value)"
              @click.stop="toggleKnowledge(item.value)"
            >
              <span>{{ item.label }}</span>
              <Check
                v-if="isSelected(item.value)"
                class="chat-capability__knowledge-check"
              />
            </button>
          </div>
          <div v-else class="chat-capability__empty">
            {{ loading ? '加载中' : '暂无可选知识库' }}
          </div>
        </div>
      </div>
    </ElPopover>
  </div>
</template>

<style scoped>
.chat-capability {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.chat-capability__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}

.chat-capability__chip {
  display: inline-flex;
  align-items: center;
  max-width: 220px;
  min-height: 28px;
  gap: 6px;
  padding: 0 8px;
  color: var(--el-color-primary);
  background: var(--el-color-primary-light-9);
  border: 1px solid var(--el-color-primary-light-7);
  border-radius: 999px;
}

.chat-capability__chip-icon {
  width: 14px;
  height: 14px;
  flex: none;
}

.chat-capability__chip-label {
  min-width: 0;
  overflow: hidden;
  font-size: 12px;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-capability__chip-remove,
.chat-capability__trigger,
.chat-capability__menu-item,
.chat-capability__knowledge-item {
  font: inherit;
}

.chat-capability__chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  color: inherit;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: 999px;
}

.chat-capability__chip-remove:hover:not(:disabled),
.chat-capability__chip-remove:focus-visible {
  background: var(--el-color-primary-light-8);
  outline: none;
}

.chat-capability__chip-remove :deep(.el-icon),
.chat-capability__chip-remove svg {
  width: 12px;
  height: 12px;
}

.chat-capability__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  color: var(--el-text-color-secondary);
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: 999px;
  transition:
    background-color 0.16s ease,
    color 0.16s ease;
}

.chat-capability__trigger:hover:not(:disabled),
.chat-capability__trigger:focus-visible,
.chat-capability__trigger.is-open {
  color: var(--el-color-primary);
  background: var(--el-fill-color-light);
  outline: none;
}

.chat-capability__trigger:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.chat-capability__trigger svg {
  width: 18px;
  height: 18px;
}

.chat-capability__menu,
.chat-capability__knowledge-panel {
  padding: 4px;
}

.chat-capability__menu {
  position: relative;
}

.chat-capability__menu-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 36px;
  padding: 0 8px;
  color: var(--el-text-color-primary);
  text-align: left;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: 12px;
}

.chat-capability__menu-item:hover:not(:disabled),
.chat-capability__menu-item:focus-visible,
.chat-capability__menu-item.is-open {
  background: var(--el-fill-color-light);
  outline: none;
}

.chat-capability__menu-item:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.chat-capability__menu-icon,
.chat-capability__menu-arrow {
  width: 16px;
  height: 16px;
  color: var(--el-text-color-secondary);
}

.chat-capability__knowledge-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 32px;
  padding: 0 8px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

.chat-capability__knowledge-panel {
  position: absolute;
  bottom: -2px;
  left: calc(100% + 4px);
  width: 296px;
  background: var(--el-bg-color-overlay);
  border-radius: 14px;
  box-shadow: var(--el-box-shadow-light);
  box-sizing: border-box;
  z-index: 1;
}

.chat-capability__knowledge-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 260px;
  overflow: auto;
}

.chat-capability__knowledge-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 36px;
  gap: 12px;
  padding: 0 10px;
  color: var(--el-text-color-primary);
  text-align: left;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: 8px;
}

.chat-capability__knowledge-item span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-capability__knowledge-item:hover:not(:disabled),
.chat-capability__knowledge-item:focus-visible,
.chat-capability__knowledge-item.is-active {
  background: var(--el-fill-color-light);
  outline: none;
}

.chat-capability__knowledge-item.is-active {
  color: var(--el-color-primary);
}

.chat-capability__knowledge-item:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.chat-capability__knowledge-check {
  width: 15px;
  height: 15px;
  flex: none;
}

.chat-capability__empty {
  padding: 16px 10px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

:global(.chat-capability-popper) {
  width: 120px !important;
  min-width: 120px !important;
  overflow: visible !important;
  padding: 4px !important;
  border-radius: 12px !important;
  box-sizing: border-box;
}

:global(.chat-capability-popper .chat-capability__menu) {
  padding: 0;
}

:global(.chat-capability-popper.el-popper) {
  transition:
    opacity 0.08s ease,
    transform 0.08s ease !important;
}
</style>
