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

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

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

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

const MAX_EXTRA_KNOWLEDGE_COUNT = 3;
const knowledgePanelOpen = ref(false);

const props = withDefaults(
  defineProps<{
    boundKnowledges?: KnowledgeView[];
    selectedExtraKnowledges?: KnowledgeView[];
    extraKnowledgeIds?: string[];
    extraKnowledgeOptions?: KnowledgeOption[];
    disabled?: boolean;
    knowledgeDisabled?: boolean;
    loading?: boolean;
    mode?: 'editable' | 'readonly';
  }>(),
  {
    boundKnowledges: () => [],
    selectedExtraKnowledges: () => [],
    extraKnowledgeIds: () => [],
    extraKnowledgeOptions: () => [],
    disabled: false,
    knowledgeDisabled: false,
    loading: false,
    mode: 'editable',
  },
);

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

const selectedExtraIdSet = computed(() => new Set(props.extraKnowledgeIds));
const hasAnyKnowledge = computed(
  () =>
    props.boundKnowledges.length > 0 || props.selectedExtraKnowledges.length > 0,
);

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

function toggleKnowledge(id: string) {
  const normalizedId = String(id);
  const nextIds = [...props.extraKnowledgeIds];
  const currentIndex = nextIds.findIndex((item) => String(item) === normalizedId);
  if (currentIndex >= 0) {
    nextIds.splice(currentIndex, 1);
    updateExtraKnowledges(nextIds);
    return;
  }
  if (nextIds.length >= MAX_EXTRA_KNOWLEDGE_COUNT) {
    return;
  }
  nextIds.push(normalizedId);
  updateExtraKnowledges(nextIds);
}

function removeExtraKnowledge(id: string) {
  updateExtraKnowledges(
    props.extraKnowledgeIds.filter((item) => String(item) !== String(id)),
  );
}

function isKnowledgeSelected(id: string) {
  return selectedExtraIdSet.value.has(String(id));
}

function isKnowledgeDisabled(id: string) {
  if (props.disabled || props.knowledgeDisabled || props.loading) {
    return true;
  }
  return (
    props.extraKnowledgeIds.length >= MAX_EXTRA_KNOWLEDGE_COUNT &&
    !isKnowledgeSelected(id)
  );
}
</script>

<template>
  <div
    v-if="mode === 'editable' || hasAnyKnowledge"
    class="context-rail"
    :class="{ 'is-readonly': mode === 'readonly' }"
  >
    <div class="context-rail__row">
      <ElPopover
        v-if="mode === 'editable'"
        v-model:visible="knowledgePanelOpen"
        placement="top-start"
        :teleported="false"
        popper-class="chat-knowledge-popper"
        :show-arrow="false"
        :width="356"
        :offset="10"
        trigger="click"
      >
        <template #reference>
          <button
            type="button"
            class="context-rail__trigger"
            :disabled="disabled || knowledgeDisabled || loading"
            :class="{ 'is-open': knowledgePanelOpen }"
          >
            <Plus class="context-rail__trigger-icon" />
            <span>{{ loading ? '加载知识库中' : '知识库' }}</span>
            <ArrowDown class="context-rail__trigger-caret" />
          </button>
        </template>

        <div class="context-rail__panel">
          <div class="context-rail__panel-head">
            <span class="context-rail__panel-title">选择知识库</span>
            <span class="context-rail__panel-caption">最多 3 个</span>
          </div>

          <div
            v-if="extraKnowledgeOptions.length > 0"
            class="context-rail__option-list"
          >
            <button
              v-for="item in extraKnowledgeOptions"
              :key="item.value"
              type="button"
              class="context-rail__option"
              :class="{
                'is-active': isKnowledgeSelected(item.value),
                'is-disabled': isKnowledgeDisabled(item.value),
              }"
              :disabled="isKnowledgeDisabled(item.value)"
              @click="toggleKnowledge(item.value)"
            >
              <span class="context-rail__option-label">
                {{ item.label }}
              </span>
              <Check
                v-if="isKnowledgeSelected(item.value)"
                class="context-rail__option-check"
              />
            </button>
          </div>

          <div v-else class="context-rail__empty">
            暂无可选知识库
          </div>
        </div>
      </ElPopover>

      <div
        v-if="hasAnyKnowledge"
        class="context-rail__chips"
      >
        <span
          v-for="knowledge in boundKnowledges"
          :key="knowledge.id"
          class="context-rail__chip is-bound"
        >
          {{ knowledge.title }}
        </span>

        <span
          v-for="knowledge in selectedExtraKnowledges"
          :key="knowledge.id"
          class="context-rail__chip is-extra"
        >
          <span class="context-rail__chip-label">{{ knowledge.title }}</span>
          <button
            v-if="mode === 'editable'"
            type="button"
            class="context-rail__chip-remove"
            aria-label="移除知识库"
            @click="removeExtraKnowledge(knowledge.id)"
          >
            <Close />
          </button>
        </span>
      </div>
    </div>
  </div>
</template>

<style scoped>
.context-rail {
  min-width: 0;
}

.context-rail__row {
  display: flex;
  gap: 10px;
  align-items: center;
  min-width: 0;
  flex-wrap: wrap;
}

.context-rail__trigger {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  min-height: 32px;
  padding: 0 12px;
  font-size: 12px;
  font-weight: 600;
  color: hsl(var(--text-strong));
  border: 1px solid hsl(var(--divider-faint) / 0.86);
  border-radius: 999px;
  background: hsl(var(--surface-panel));
  transition:
    border-color 0.18s ease,
    background-color 0.18s ease,
    color 0.18s ease;
}

.context-rail__trigger:hover:not(:disabled) {
  border-color: hsl(var(--primary) / 0.22);
  background: hsl(var(--surface-subtle));
}

.context-rail__trigger.is-open {
  border-color: hsl(var(--primary) / 0.24);
  background: hsl(var(--surface-subtle));
}

.context-rail__trigger:focus-visible,
.context-rail__option:focus-visible,
.context-rail__chip-remove:focus-visible {
  outline: 2px solid hsl(var(--primary) / 0.28);
  outline-offset: 2px;
}

.context-rail__trigger:disabled {
  cursor: not-allowed;
  opacity: 0.68;
}

.context-rail__trigger-icon,
.context-rail__trigger-caret {
  width: 14px;
  height: 14px;
  color: hsl(var(--text-muted));
}

.context-rail__chips {
  display: flex;
  gap: 8px;
  align-items: center;
  min-width: 0;
  flex-wrap: wrap;
}

.context-rail__chip {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  max-width: min(100%, 220px);
  min-height: 32px;
  padding: 0 12px;
  overflow: hidden;
  font-size: 12px;
  font-weight: 500;
  color: hsl(var(--text-muted));
  border: 1px solid hsl(var(--divider-faint) / 0.84);
  border-radius: 999px;
  background: hsl(var(--surface-panel));
}

.context-rail__chip.is-extra {
  color: hsl(var(--text-strong));
  border-color: hsl(var(--primary) / 0.18);
  background: hsl(var(--primary) / 0.06);
}

.context-rail__chip-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.context-rail__chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  color: hsl(var(--text-muted));
  border: none;
  border-radius: 999px;
  background: transparent;
}

.context-rail__chip-remove:hover {
  color: hsl(var(--text-strong));
  background: hsl(var(--surface-panel) / 0.7);
}

.context-rail__chip-remove :deep(svg) {
  width: 12px;
  height: 12px;
}

.context-rail__panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.context-rail__panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.context-rail__panel-title {
  font-size: 13px;
  font-weight: 650;
  color: hsl(var(--text-strong));
}

.context-rail__panel-caption {
  font-size: 11px;
  color: hsl(var(--text-muted));
}

.context-rail__option-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.context-rail__option {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 11px 12px;
  text-align: left;
  color: hsl(var(--text-strong));
  border: 1px solid transparent;
  border-radius: 12px;
  background: hsl(var(--surface-subtle) / 0.82);
  transition:
    border-color 0.18s ease,
    background-color 0.18s ease,
    color 0.18s ease;
}

.context-rail__option:hover:not(:disabled) {
  border-color: hsl(var(--primary) / 0.16);
  background: hsl(var(--surface-panel));
}

.context-rail__option.is-active {
  border-color: hsl(var(--primary) / 0.18);
  background: hsl(var(--primary) / 0.07);
}

.context-rail__option.is-disabled {
  cursor: not-allowed;
  opacity: 0.58;
}

.context-rail__option-label {
  overflow: hidden;
  font-size: 12px;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.context-rail__option-check {
  flex: none;
  width: 14px;
  height: 14px;
  color: hsl(var(--primary));
}

.context-rail__empty {
  padding: 2px 0;
  font-size: 12px;
  text-align: left;
  color: hsl(var(--text-muted));
}

:global(.chat-knowledge-popper.el-popper) {
  padding: 12px;
  border: 1px solid hsl(var(--divider-faint) / 0.88);
  border-radius: 18px;
  background:
    linear-gradient(180deg, hsl(var(--surface-panel) / 0.98) 0%, hsl(var(--surface-subtle) / 0.96) 100%);
  box-shadow: 0 18px 40px -32px hsl(var(--foreground) / 0.22);
  backdrop-filter: blur(18px);
}

:global(.chat-knowledge-popper.el-popper .el-popper__arrow) {
  display: none;
}

@media (max-width: 768px) {
  .context-rail__row {
    align-items: stretch;
  }

  .context-rail__trigger {
    justify-content: center;
    width: 100%;
  }
}
</style>
