<template>
  <div class="knowledge-page">
    <el-row :gutter="20">
      <el-col :span="16">
        <el-card>
          <template #header>
            <div class="card-header">
              <span>知识库文档</span>
              <div style="display: flex; gap: 8px; align-items: center">
                <el-tag type="info" size="small">共 {{ stats.total_files || 0 }} 个文件 / {{ stats.total_chunks || 0 }} 个分块</el-tag>
                <el-upload :http-request="uploadDoc" :show-file-list="false" accept=".pdf,.docx,.doc,.xlsx,.xls,.txt,.md">
                  <el-button type="primary" size="small">上传文档</el-button>
                </el-upload>
              </div>
            </div>
          </template>

          <el-table :data="documents" v-loading="loading" stripe empty-text="暂无文档，请上传或手动索引文本">
            <el-table-column prop="source" label="来源文件" min-width="200" show-overflow-tooltip />
            <el-table-column prop="chunk_count" label="分块数" width="90" sortable>
              <template #default="{ row }">
                <el-tag size="small">{{ row.chunk_count }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column label="内容预览" min-width="250" show-overflow-tooltip>
              <template #default="{ row }">
                <span style="color: #666; font-size: 12px">{{ row.preview || '无预览' }}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="120" fixed="right">
              <template #default="{ row }">
                <el-popconfirm title="确认删除该文档的所有分块？" @confirm="deleteDoc(row)" confirm-button-text="删除" cancel-button-text="取消">
                  <template #reference>
                    <el-button size="small" type="danger" link>删除</el-button>
                  </template>
                </el-popconfirm>
              </template>
            </el-table-column>
          </el-table>

          <div v-if="documents.length > 0" style="margin-top: 12px; color: #909399; font-size: 12px; text-align: right">
            提示：删除操作会移除该来源下的所有向量分块，不可恢复
          </div>
        </el-card>
      </el-col>

      <el-col :span="8">
        <el-card>
          <template #header>检索测试</template>
          <el-input
            v-model="query"
            placeholder="输入问题检索知识库..."
            @keyup.enter="doSearch"
            clearable
            style="margin-bottom: 12px"
          >
            <template #append>
              <el-button @click="doSearch" :loading="searching">检索</el-button>
            </template>
          </el-input>

          <div v-if="results.length > 0" class="results-container">
            <div v-for="(r, i) in results" :key="i" class="result-item">
              <div class="result-header">
                <el-tag size="small" :type="r.score > 0.7 ? 'success' : r.score > 0.5 ? 'warning' : 'info'">
                  相关度 {{ (r.score * 100).toFixed(1) }}%
                </el-tag>
                <span class="result-source">来源: {{ r.source }}</span>
              </div>
              <div class="result-content">{{ r.content }}</div>
            </div>
          </div>
          <el-empty v-else-if="searched && !searching" description="未找到相关内容" :image-size="60" />
          <div v-else-if="!searched" class="search-placeholder">
            <el-icon :size="40" color="#c0c4cc"><Search /></el-icon>
            <p>输入问题后点击检索</p>
          </div>
        </el-card>

        <el-card style="margin-top: 20px">
          <template #header>手动索引</template>
          <el-input
            v-model="manualText"
            type="textarea"
            :rows="4"
            placeholder="粘贴需要索引的文本内容..."
            maxlength="10000"
            show-word-limit
          />
          <el-input v-model="manualSource" placeholder="来源标识（如：产品手册-v2）" style="margin-top: 8px" />
          <el-button
            type="primary"
            @click="indexText"
            :loading="indexing"
            :disabled="!manualText.trim()"
            style="width: 100%; margin-top: 8px"
          >索引文本</el-button>
        </el-card>

        <el-card style="margin-top: 20px">
          <template #header>知识库状态</template>
          <el-descriptions :column="1" border size="small">
            <el-descriptions-item label="状态">
              <el-tag :type="stats.status === 'initialized' ? 'success' : 'danger'" size="small">
                {{ stats.status === 'initialized' ? '正常' : '异常' }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="集合名称">{{ stats.collection_name || '-' }}</el-descriptions-item>
            <el-descriptions-item label="向量维度">{{ stats.dimensions || '-' }}</el-descriptions-item>
            <el-descriptions-item label="总分块数">{{ stats.total_chunks || 0 }}</el-descriptions-item>
            <el-descriptions-item label="文件数量">{{ stats.total_files || 0 }}</el-descriptions-item>
          </el-descriptions>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import { ragApi } from '@/api'

const loading = ref(false)
const searching = ref(false)
const indexing = ref(false)
const searched = ref(false)
const documents = ref<any[]>([])
const query = ref('')
const results = ref<any[]>([])
const manualText = ref('')
const manualSource = ref('manual')
const stats = ref<any>({})

async function loadStats() {
  try {
    const res: any = await ragApi.getStats()
    stats.value = res?.data || {}
  } catch {
    stats.value = { status: 'error', total_chunks: 0, total_files: 0 }
  }
}

async function loadDocs() {
  loading.value = true
  try {
    const res: any = await ragApi.getDocuments()
    documents.value = (res?.data || []).map((d: any) => ({
      source: d.source,
      chunk_count: d.chunk_count || 0,
      preview: d.preview || '',
    }))
    await loadStats()
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || '获取文档列表失败')
  } finally {
    loading.value = false
  }
}

async function uploadDoc(options: any) {
  try {
    await ragApi.upload(options.file)
    ElMessage.success('文档已上传并开始索引')
    await loadDocs()
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || '上传失败')
  }
}

async function doSearch() {
  if (!query.value.trim()) return
  searching.value = true
  searched.value = true
  try {
    const res: any = await ragApi.search(query.value.trim(), 5)
    results.value = Array.isArray(res?.data) ? res.data : []
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || '检索失败')
    results.value = []
  } finally {
    searching.value = false
  }
}

async function indexText() {
  if (!manualText.value.trim()) return
  indexing.value = true
  try {
    await ragApi.indexText({ text: manualText.value, source: manualSource.value || 'manual' })
    ElMessage.success('文本已索引到知识库')
    manualText.value = ''
    manualSource.value = 'manual'
    await loadDocs()
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || '索引失败')
  } finally {
    indexing.value = false
  }
}

async function deleteDoc(row: any) {
  try {
    await ragApi.deleteDocument(row.source)
    ElMessage.success(`已删除 "${row.source}" 的所有分块`)
    await loadDocs()
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || '删除失败')
  }
}

onMounted(() => {
  loadDocs()
})
</script>

<style scoped>
.knowledge-page {
  padding: 0;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.results-container {
  max-height: 350px;
  overflow-y: auto;
}
.result-item {
  padding: 10px 0;
  border-bottom: 1px solid #f0f0f0;
}
.result-item:last-child {
  border-bottom: none;
}
.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}
.result-source {
  font-size: 11px;
  color: #909399;
}
.result-content {
  font-size: 13px;
  line-height: 1.6;
  color: #303133;
  max-height: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search-placeholder {
  text-align: center;
  padding: 30px 0;
  color: #c0c4cc;
}
.search-placeholder p {
  margin-top: 8px;
  font-size: 13px;
}
</style>