
<template>
  <div class="search-engine-container">
    <div class="header-section">
      <div class="title-info">
        <h2>检索引擎</h2>
        <p class="subtitle">检索知识库中的内容</p>
      </div>
      <div class="header-right">
        <!-- 可以在这里放用户信息或其他按钮 -->
      </div>
    </div>

    <!-- Search Form Card -->
    <el-card class="search-card" shadow="never">
      <div class="search-form-container">
        <!-- 顶部行：知识库 + 检索模式 + 关键字 -->
        <div class="search-form-row main-row">
            <div class="form-item kb-select">
                <div class="label">知识库</div>
                <el-select 
                    v-model="searchForm.kb_id" 
                    placeholder="选择知识库" 
                    style="width: 100%"
                    clearable
                    @change="handleKbChange"
                >
                    <el-option 
                        v-for="kb in kbList" 
                        :key="kb.id" 
                        :label="kb.name" 
                        :value="kb.collection_name_children || kb.collection_name_parent || kb.collection_name" 
                    >
                        <span>{{ kb.name }}</span>
                    </el-option>
                </el-select>
            </div>
            
            <div class="form-item search-mode">
                <div class="label">检索模式</div>
                <el-select 
                    v-model="searchForm.mode" 
                    placeholder="请选择" 
                    style="width: 100%"
                    @change="handleModeChange"
                >
                    <el-option label="简单模式" value="simple" />
                    <el-option label="高级模式" value="advanced" />
                </el-select>
            </div>

            <div class="form-item keyword-input">
                <div class="label">检索关键字</div>
                <el-input 
                    v-model="searchForm.query" 
                    placeholder="请输入检索内容..." 
                    clearable
                    @keyup.enter="handleSearch"
                    :disabled="!searchForm.kb_id"
                >
                    <template #append>
                        <el-button :icon="Search" @click="handleSearch" :disabled="!searchForm.kb_id">
                            检索
                        </el-button>
                    </template>
                </el-input>
            </div>
        </div>

        <!-- 文档范围过滤 (简单模式可见) -->
        <div class="search-form-row secondary-row" v-if="searchForm.kb_id">
            <div class="form-item doc-filter">
                <div class="label">文档范围过滤</div>
                <el-select 
                    v-model="searchForm.doc_names" 
                    placeholder="默认检索全部文档，可选择特定文档进行范围限定" 
                    multiple
                    filterable
                    remote
                    clearable
                    collapse-tags
                    collapse-tags-tooltip
                    :remote-method="loadDocOptions"
                    :loading="docLoading"
                    style="width: 100%"
                    @focus="() => loadDocOptions('')"
                >
                    <el-option
                        v-for="item in docOptions"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    />
                </el-select>
            </div>
        </div>

        <!-- 高级过滤区域 (仅在高级模式显示) -->
        <div v-if="searchForm.mode === 'advanced'" class="advanced-filter-area">
            <!-- 顶部操作栏：标题 + 添加按钮 -->
            <div class="filter-header">
                <div class="filter-section-title">元数据过滤条件</div>
                <el-button type="primary" link :icon="Plus" size="small" @click="addFilter">添加条件</el-button>
            </div>
            
            <div class="filter-list">
                <div v-for="(filter, index) in searchForm.filters" :key="index" class="filter-item">
                    <el-row :gutter="10" align="middle">
                        <el-col :span="10">
                            <el-select 
                                v-model="filter.field" 
                                placeholder="选择字段" 
                                style="width: 100%"
                                clearable
                                :disabled="!searchForm.kb_id"
                            >
                                <el-option 
                                    v-for="field in metadataFields" 
                                    :key="field.id" 
                                    :label="field.field_zh_name + ' (' + field.field_en_name + ')'" 
                                    :value="field.field_en_name" 
                                />
                            </el-select>
                        </el-col>
                        <el-col :span="1" style="text-align: center; color: #909399;">=</el-col>
                        <el-col :span="11">
                            <el-input 
                                v-model="filter.value" 
                                placeholder="输入值" 
                                :disabled="!filter.field"
                                @keyup.enter="handleSearch"
                            />
                        </el-col>
                        <el-col :span="2" style="text-align: center;">
                            <el-button 
                                v-if="searchForm.filters.length > 1"
                                type="danger" 
                                link 
                                :icon="Delete" 
                                @click="removeFilter(index)"
                            />
                        </el-col>
                    </el-row>
                </div>
            </div>
        </div>
      </div>
    </el-card>

    <!-- Results Table Card -->
    <el-card class="result-card" shadow="never" v-if="hasSearched">
      <el-table :data="tableData" v-loading="loading" style="width: 100%">
        <el-table-column label="知识库" width="150" show-overflow-tooltip>
            <template #default="{ row }">
                <span>{{ getKbName(row.kb_name) }}</span>
            </template>
        </el-table-column>
        <el-table-column label="文档名称" width="200" show-overflow-tooltip>
             <template #default="{ row }">
                 <span v-if="docNamesMap[row.document_id]">{{ docNamesMap[row.document_id] }}</span>
                 <span v-else>{{ row.doc_name }}</span>
             </template>
        </el-table-column>
        <el-table-column prop="content" label="检索片段内容" min-width="400">
            <template #default="{ row }">
                <el-tooltip
                    effect="light"
                    placement="top-start"
                    :disabled="!row.content || row.content.length <= 200"
                >
                    <template #content>
                        <div class="tooltip-content-scroll" v-html="highlightKeyword(row.content)"></div>
                    </template>
                    <div class="snippet-content" v-html="highlightKeyword(truncateText(row.content, 200))"></div>
                </el-tooltip>
            </template>
        </el-table-column>
        <el-table-column label="元数据信息" width="250" show-overflow-tooltip>
             <template #default="{ row }">
                 <span>{{ formatMetaInfo(row) }}</span>
             </template>
        </el-table-column>
        <el-table-column prop="score" label="相似度" width="100">
            <template #default="{ row }">
                <el-tag :type="getScoreType(row.score)">{{ row.score }}%</el-tag>
            </template>
        </el-table-column>
        <el-table-column label="操作" width="100" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" @click="handleDetail(row)">
              查看详情
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination-container" v-if="total > 0">
        <div class="pagination-info">
            显示 {{ (currentPage - 1) * pageSize + 1 }} 到 
            {{ Math.min(currentPage * pageSize, total) }} 条，
            共 {{ total }} 条记录
        </div>
        <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :total="total"
          :page-sizes="[10, 20, 50]"
          layout="prev, pager, next, sizes"
          @size-change="handleSearch"
          @current-change="handleSearch"
        />
      </div>
    </el-card>
    
    <div v-else-if="!searchForm.kb_id" class="empty-placeholder">
        <el-empty description="请选择知识库并输入关键字进行检索" />
    </div>

    <!-- Detail Dialog -->
    <el-dialog v-model="detailVisible" title="片段详情" width="800px">
        <div class="detail-content">
            <div class="detail-item">
                <span class="label">知识库:</span>
                <span>{{ getKbName(currentDetail?.kb_name) }}</span>
            </div>
            <div class="detail-item">
                <span class="label">文档:</span>
                <span>{{ currentDetail?.doc_name }}</span>
            </div>
            <div class="detail-item">
                <span class="label">相似度:</span>
                <span>{{ currentDetail?.score }}%</span>
            </div>
            <div class="view-content-section" v-if="currentDetail?.parent_id && currentDetail?.parent_id !== '0'">
                <div class="section-title">
                    <el-icon><Connection /></el-icon> 父段内容
                </div>
                <div v-loading="parentLoading">
                    <el-tabs v-if="parentSegments.length > 1" v-model="activeParentTab" type="card">
                        <el-tab-pane
                            v-for="(seg, idx) in parentSegments"
                            :key="seg.id || idx"
                            :label="`父段片段 ${idx + 1}`"
                            :name="String(idx)"
                        >
                            <div class="content-box parent-content">{{ seg.content || '暂无内容' }}</div>
                        </el-tab-pane>
                    </el-tabs>
                    <div v-else class="content-box parent-content">{{ parentSegments[0]?.content || '暂无内容' }}</div>
                </div>
            </div>
            <div class="detail-item full-content">
                <span class="label">完整内容:</span>
                <div class="text-box">{{ currentDetail?.content }}</div>
            </div>
            <div class="detail-item">
                <span class="label">元数据:</span>
                <span>{{ formatMetaInfo(currentDetail) }}</span>
            </div>
        </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { Search, Plus, Delete, Connection } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { getKnowledgeBases, getKnowledgeBaseMetadata, type KnowledgeBase } from '@/api/knowledge-base'
import { searchKnowledgeBase, type KBSearchResultItem } from '@/api/search-engine'
import { getSnippetDetail } from '@/api/snippet'
import { documentApi } from '@/api/document'

// Data
const kbList = ref<KnowledgeBase[]>([])
const metadataFields = ref<any[]>([]) // Store available metadata fields for selected KB
const loading = ref(false)
const hasSearched = ref(false)
const tableData = ref<KBSearchResultItem[]>([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)

const searchForm = reactive({
  kb_id: '',
  mode: 'simple',
  filters: [{ field: '', value: '' }] as { field: string, value: string }[],
  query: '',
  doc_names: [] as string[] // 文档名称过滤
})

const docOptions = ref<{label: string, value: string}[]>([])
const docLoading = ref(false)

const loadDocOptions = async (query: string) => {
    docLoading.value = true
    try {
        const res = await documentApi.getList({
            page: 1,
            size: 50, 
            keyword: query,
        }, true)

        if (res.code === 0) {
            // 映射为 label (title) 和 value (title) - 这里我们用 title 作为过滤值
            // 因为 Milvus 中存的是 doc_name/title，而不是 ID
            docOptions.value = res.data.items.map(item => ({
                label: item.title,
                value: item.title 
            }))
        }
    } catch (error) {
        console.error("加载文档列表失败", error)
    } finally {
        docLoading.value = false
    }
}

const detailVisible = ref(false)
const currentDetail = ref<KBSearchResultItem | null>(null)
const parentSegments = ref<any[]>([])
const parentLoading = ref(false)
const activeParentTab = ref('0')

// Methods
const handleModeChange = () => {
    // Reset advanced fields when switching to simple
    if (searchForm.mode === 'simple') {
        searchForm.filters = [{ field: '', value: '' }]
    }
}

const addFilter = () => {
    searchForm.filters.push({ field: '', value: '' })
}

const removeFilter = (index: number) => {
    searchForm.filters.splice(index, 1)
}

const loadKBs = async () => {
  try {
    const res = await getKnowledgeBases({ page: 1, page_size: 100 }) // Load all KBs (simplified)
    kbList.value = res.data
  } catch (error) {
    console.error(error)
  }
}

const handleKbChange = async () => {
    // Reset search when KB changes
    hasSearched.value = false
    tableData.value = []
    total.value = 0
    
    // Reset metadata selection
    searchForm.filters = [{ field: '', value: '' }]
    metadataFields.value = []
    
    if (searchForm.kb_id) {
        // Find selected KB object to get ID (kb_id in form is collection_name)
        const selectedKb = kbList.value.find(k => 
            k.collection_name_children === searchForm.kb_id || 
            k.collection_name_parent === searchForm.kb_id ||
            k.collection_name === searchForm.kb_id
        )
        if (selectedKb) {
            try {
                const res = await getKnowledgeBaseMetadata(selectedKb.id)
                // 确保后端返回的数据格式正确
                if (res.code === 0) {
                    if (Array.isArray(res.data)) {
                        metadataFields.value = res.data
                    } else if (res.data && Array.isArray(res.data.metadata_fields)) {
                        metadataFields.value = res.data.metadata_fields
                    } else {
                        metadataFields.value = []
                    }
                } else {
                    console.warn("Invalid metadata response:", res)
                    metadataFields.value = []
                }
            } catch (error) {
                console.error("Failed to load metadata fields", error)
                metadataFields.value = []
            }
        }
    }
}

const docNamesMap = ref<Record<string, string>>({})

const formatMetaInfo = (row: any) => {
    // 优先展示 metadata 字段中的信息
    if (row.metadata) {
        // 如果是 JSON 对象，尝试格式化展示
        if (typeof row.metadata === 'object') {
             const displayParts = []
             for (const [key, value] of Object.entries(row.metadata)) {
                 const valStr = typeof value === 'object' ? JSON.stringify(value) : String(value)
                 displayParts.push(`${key}: ${valStr}`)
             }
             if (displayParts.length > 0) return displayParts.join(' | ')
        } else if (typeof row.metadata === 'string') {
            try {
                const metaObj = JSON.parse(row.metadata)
                const displayParts = []
                for (const [key, value] of Object.entries(metaObj)) {
                    const valStr = typeof value === 'object' ? JSON.stringify(value) : String(value)
                    displayParts.push(`${key}: ${valStr}`)
                }
                if (displayParts.length > 0) return displayParts.join(' | ')
            } catch (e) {
                return String(row.metadata)
            }
        }
    }
    // 如果 row 本身有 vector 属性，也不显示在 meta_info 中
    // 这里只处理了 metadata 字段内的
    return row.meta_info || '-'
}

const loadDocNames = async (docIds: string[]) => {
    if (docIds.length === 0) return
    
    // 过滤掉已经有的
    const missingIds = docIds.filter(id => !docNamesMap.value[id] && id)
    if (missingIds.length === 0) return

    // 批量查询文档详情比较低效，documentApi 如果有批量接口最好
    // 暂时循环查询，或者如果 documentApi.getList 支持 ids 参数
    // 假设我们只能单个查，为了性能，我们这里只查前 20 个 unique 的
    
    // 更好的方式：如果后端 search 接口能直接返回 doc_name 最好。
    // 但用户要求 "文档来源就根据这个片段的document_id去数据库里面查找"
    // 意味着我们需要前端二次查询或者后端聚合。
    // 为了前端响应速度，我们异步查询。
    
    for (const id of missingIds) {
        try {
            // 这里用 getDetail 查
            const res = await documentApi.getDetail(id)
            if (res.code === 0 && res.data) {
                docNamesMap.value[id] = res.data.title
            } else {
                 docNamesMap.value[id] = '未知文档'
            }
        } catch (e) {
            console.error(`加载文档 ${id} 失败`, e)
        }
    }
}

const handleSearch = async () => {
  if (!searchForm.kb_id) {
    ElMessage.warning('请选择知识库')
    return
  }
  
  // If keyword is empty but KB is selected, user might want to see all or needs keyword?
  // Requirement says "search based on keyword", but usually empty keyword is allowed or blocked.
  // We will allow it but maybe warn if strict. Let's assume standard search behavior.
  
  loading.value = true
  hasSearched.value = true
  
  try {
    // 处理多重过滤
    // 后端目前可能只支持单一 metadata_field/value，或者我们需要修改后端接口支持 filters 数组
    // 这里我们先转换成后端能理解的格式，或者假设后端已更新
    // 假设后端接口 searchKnowledgeBase 支持 filters 参数: { field: string, value: string }[]
    
    // 过滤掉空的条件
    const validFilters = searchForm.mode === 'advanced' 
        ? searchForm.filters.filter(f => f.field && f.value)
        : []
    
    // 将文档过滤也作为一种特殊的 filter 加入
    // 注意：即便是简单模式，如果用户选了文档，也应该生效
    if (searchForm.doc_names.length > 0) {
        // 对于多选文档，我们需要构建 OR 逻辑，但目前的 filters 结构是 AND
        // 我们可以约定 field 为 "doc_name_in"，value 为逗号分隔的字符串
        validFilters.push({
            field: 'doc_name_in',
            value: JSON.stringify(searchForm.doc_names)
        })
    }
        
    const res = await searchKnowledgeBase({
        kb_id: searchForm.kb_id,
        query: searchForm.query || '', 
        // 传递 filters 数组 (需要后端支持，或者我们在前端做兼容处理)
        // 为了兼容旧接口，如果只有一个 filter，传旧参数；如果有多个，传新参数 filters
        metadata_field: validFilters.length === 1 && validFilters[0].field !== 'doc_name_in' ? validFilters[0].field : undefined,
        metadata_value: validFilters.length === 1 && validFilters[0].field !== 'doc_name_in' ? validFilters[0].value : undefined,
        filters: validFilters.length > 0 ? validFilters : undefined,
        
        top_k: pageSize.value, 
        page: currentPage.value,
        page_size: pageSize.value,
        metric_type: 'hybrid', 
    })
    
    tableData.value = res.data.results
    total.value = res.data.total
    
    // 异步加载文档名称
    const docIds = res.data.results.map((r: any) => r.document_id).filter((id: string) => id)
    // 不阻塞 UI
    loadDocNames(docIds)
    
  } catch (error: any) {
    console.error(error)
    ElMessage.error(error.message || '检索失败，请检查配置或稍后重试')
  } finally {
    loading.value = false
  }
}

const handleDetail = (row: KBSearchResultItem) => {
    currentDetail.value = row
    parentSegments.value = []
    parentLoading.value = false
    activeParentTab.value = '0'
    if (row.parent_id) {
        parentLoading.value = true
        getSnippetDetail(row.kb_name, row.parent_id)
            .then((res: any) => {
                if (res.code === 0 && res.data) {
                    if (Array.isArray(res.data.parent_segments) && res.data.parent_segments.length > 0) {
                        parentSegments.value = res.data.parent_segments
                    } else if (res.data.parent_content) {
                        parentSegments.value = [{ id: '', content: res.data.parent_content }]
                    }
                }
            })
            .finally(() => {
                parentLoading.value = false
            })
    }
    detailVisible.value = true
}

const getKbName = (collectionName?: string) => {
    if (!collectionName) return '-'
    const matched = kbList.value.find(k =>
        k.collection_name_children === collectionName ||
        k.collection_name_parent === collectionName ||
        (k as any).collection_name === collectionName
    )
    return matched?.name || collectionName
}

const getScoreType = (score: number) => {
    if (score >= 90) return 'success'
    if (score >= 70) return 'warning'
    return 'info'
}

const highlightKeyword = (text: string) => {
    if (!searchForm.query) return text
    const keyword = searchForm.query
    const regex = new RegExp(keyword, 'gi')
    return text.replace(regex, `<span style="color: #409eff; font-weight: bold;">$&</span>`)
}

const truncateText = (text: string, length: number) => {
    if (!text) return ''
    if (text.length <= length) return text
    return text.slice(0, length) + '...'
}

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

<style scoped>
.search-engine-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: calc(100vh - 84px);
}

.view-content-section {
    margin-top: 20px;
}

.view-content-section .section-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    margin-bottom: 12px;
    font-size: 16px;
    color: #303133;
    border-left: 4px solid #409EFF;
    padding-left: 10px;
}

.content-box {
    background-color: #f5f7fa;
    padding: 15px;
    border-radius: 4px;
    border: 1px solid #e4e7ed;
    color: #606266;
    line-height: 1.6;
    max-height: 400px;
    overflow-y: auto;
    white-space: pre-wrap;
    word-break: break-all;
}

.parent-content {
    background-color: #fcf6ec;
    border-color: #f3d19e;
    color: #e6a23c;
}

.header-section {
  margin-bottom: 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.title-info h2 {
  font-size: 20px;
  font-weight: 600;
  color: #303133;
  margin: 0;
  display: inline-block;
  margin-right: 12px;
}

.subtitle {
  display: inline-block;
  color: #909399;
  font-size: 14px;
  margin: 0;
}

.search-card {
  margin-bottom: 20px;
  border-radius: 4px;
}

.search-form-row {
  display: flex;
  gap: 20px;
  align-items: flex-end;
}

.search-form-row.main-row {
    align-items: flex-end;
    margin-bottom: 0;
}

.kb-select {
    flex: 0 0 250px;
}

.search-mode {
    flex: 0 0 150px;
}

.keyword-input {
    flex: 1;
}

.form-item .label {
  font-size: 13px;
  color: #606266;
  margin-bottom: 8px;
  font-weight: 500;
}

.advanced-filter-area {
    margin-top: 20px;
    padding: 20px;
    border-top: 1px solid #ebeef5;
    background-color: #fafafa;
    border-radius: 4px;
}

.filter-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}

.filter-title {
    font-size: 13px;
    font-weight: 600;
    color: #606266;
}

.filter-list {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.filter-item {
    width: calc(33.33% - 8px); /* 一行三个 */
    background-color: #f5f7fa;
    padding: 10px;
    border-radius: 4px;
}

@media screen and (max-width: 1200px) {
    .filter-item {
        width: calc(50% - 6px); /* 一行两个 */
    }
}

@media screen and (max-width: 768px) {
    .filter-item {
        width: 100%; /* 一行一个 */
    }
}

.result-card {
  border-radius: 4px;
}

.snippet-content {
    line-height: 1.5;
    color: #606266;
    word-break: break-all;
}

.tooltip-content-scroll {
    max-width: 500px;
    max-height: 400px;
    overflow-y: auto;
    line-height: 1.6;
    word-break: break-all;
}

.pagination-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 20px;
}

.pagination-info {
    color: #909399;
    font-size: 13px;
}

.empty-placeholder {
    padding: 40px;
    background: #fff;
    border-radius: 4px;
    display: flex;
    justify-content: center;
    align-items: center;
}

.detail-content {
    padding: 10px;
}

.detail-item {
    margin-bottom: 16px;
    display: flex;
}

.detail-item .label {
    font-weight: bold;
    width: 80px;
    flex-shrink: 0;
    color: #606266;
}

.detail-item.full-content {
    flex-direction: column;
}

.detail-item.full-content .label {
    margin-bottom: 8px;
}

.text-box {
    background: #f5f7fa;
    padding: 12px;
    border-radius: 4px;
    line-height: 1.6;
    max-height: 300px;
    overflow-y: auto;
    white-space: pre-wrap;
}
</style>
