<template>
<div>
  <HeaderComponent
    :title="database.name || '数据库信息'"
    :loading="state.databaseLoading"
  >
    <template #description>
      <div class="database-info">
        <a-tag color="blue" v-if="database.embed_model">{{ database.embed_model }}</a-tag>
        <a-tag color="green" v-if="database.dimension">{{ database.dimension }}</a-tag>
        <span class="row-count">{{ database.files ? Object.keys(database.files).length : 0 }} 文件 · {{ database.db_id }}</span>
      </div>
    </template>
    <template #actions>
      <a-button type="primary" @click="backToDatabase">
        <LeftOutlined /> 返回
      </a-button>
      <a-button type="primary" @click="showEditModal">
        <EditOutlined />
      </a-button>
    </template>
  </HeaderComponent>
  <a-alert v-if="configStore.config.embed_model &&database.embed_model != configStore.config.embed_model" message="向量模型不匹配，请重新选择" type="warning" style="margin: 10px 20px;" />

  <!-- 添加编辑对话框 -->
  <a-modal v-model:open="editModalVisible" title="编辑知识库信息">
    <template #footer>
      <a-button danger @click="deleteDatabse" style="margin-right: auto; margin-left: 0;">
        <DeleteOutlined /> 删除数据库
      </a-button>
      <a-button key="back" @click="editModalVisible = false">取消</a-button>
      <a-button key="submit" type="primary" :loading="loading" @click="handleEditSubmit">确定</a-button>
    </template>
    <a-form :model="editForm" :rules="rules" ref="editFormRef" layout="vertical">
      <a-form-item label="知识库名称" name="name" required>
        <a-input v-model:value="editForm.name" placeholder="请输入知识库名称" />
      </a-form-item>
      <a-form-item label="知识库描述" name="description">
        <a-textarea v-model:value="editForm.description" placeholder="请输入知识库描述" :rows="4" />
      </a-form-item>
    </a-form>
  </a-modal>

  <!-- 分块参数配置弹窗 -->
  <a-modal v-model:open="chunkConfigModalVisible" title="分块参数配置" width="500px">
    <template #footer>
      <a-button key="back" @click="chunkConfigModalVisible = false">取消</a-button>
      <a-button key="submit" type="primary" @click="handleChunkConfigSubmit">确定</a-button>
    </template>
    <div class="chunk-config-content">
      <div class="params-info">
        <p>调整分块参数可以控制文本的切分方式，影响检索质量和文档加载效率。</p>
      </div>
      <a-form
        :model="tempChunkParams"
        name="chunkConfig"
        autocomplete="off"
        layout="vertical"
      >
        <a-form-item label="Chunk Size" name="chunk_size">
          <a-input-number v-model:value="tempChunkParams.chunk_size" :min="100" :max="10000" style="width: 100%;" />
          <p class="param-description">每个文本片段的最大字符数</p>
        </a-form-item>
        <a-form-item label="Chunk Overlap" name="chunk_overlap">
          <a-input-number v-model:value="tempChunkParams.chunk_overlap" :min="0" :max="1000" style="width: 100%;" />
          <p class="param-description">相邻文本片段间的重叠字符数</p>
        </a-form-item>
        <a-form-item label="自动索引" name="auto_indexing">
          <a-switch v-model:checked="tempChunkParams.auto_indexing" />
          <p class="param-description">分块完成后自动开始索引，生成向量并写入数据库</p>
        </a-form-item>
      </a-form>
    </div>
  </a-modal>

  <!-- 添加文件弹窗 -->
  <a-modal v-model:open="addFilesModalVisible" title="添加文件" width="800px">
    <template #footer>
      <a-button key="back" @click="addFilesModalVisible = false">取消</a-button>
      <a-button
        key="submit"
        type="primary"
        @click="chunkData"
        :loading="state.chunkLoading"
        :disabled="(uploadMode === 'file' && fileList.length === 0) || (uploadMode === 'url' && !urlList.trim())"
      >
        生成分块
      </a-button>
    </template>
    <div class="add-files-content">
      <div class="upload-header">
        <div class="source-selector">
          <div class="upload-mode-selector" @click="uploadMode = 'file'" :class="{ active: uploadMode === 'file' }">
            <FileOutlined /> 上传文件
          </div>
          <div class="upload-mode-selector" @click="uploadMode = 'url'" :class="{ active: uploadMode === 'url' }">
            <LinkOutlined /> 输入网址
          </div>
        </div>
        <div class="config-controls">
          <a-button type="dashed" @click="showChunkConfigModal">
            <SettingOutlined /> 分块参数 ({{ chunkParams.chunk_size }}/{{ chunkParams.chunk_overlap }}{{ chunkParams.auto_indexing ? '/自动索引' : '' }})
          </a-button>
        </div>
      </div>

      <div class="ocr-config">
        <a-form layout="horizontal">
          <a-form-item label="使用OCR" name="enable_ocr">
            <a-select v-model:value="chunkParams.enable_ocr" :options="enable_ocr_options" style="width: 200px;" />
            <span class="param-description">启用OCR功能，支持PDF文件的文本提取</span>
          </a-form-item>
        </a-form>
      </div>

      <!-- 文件上传区域 -->
      <div class="upload" v-if="uploadMode === 'file'">
        <a-upload-dragger
          class="upload-dragger"
          v-model:fileList="fileList"
          name="file"
          :multiple="true"
          :disabled="state.chunkLoading"
          :action="'/api/data/upload?db_id=' + databaseId"
          :headers="getAuthHeaders()"
          @change="handleFileUpload"
          @drop="handleDrop"
        >
          <p class="ant-upload-text">点击或者把文件拖拽到这里上传</p>
          <p class="ant-upload-hint">
            目前仅支持上传文本文件，如 .pdf, .txt, .md。且同名文件无法重复添加
          </p>
        </a-upload-dragger>
      </div>

      <!-- URL 输入区域 -->
      <div class="url-input" v-else>
        <a-form layout="vertical">
          <a-form-item label="网页链接 (每行一个URL)">
            <a-textarea
              v-model:value="urlList"
              placeholder="请输入网页链接，每行一个"
              :rows="6"
              :disabled="state.chunkLoading"
            />
          </a-form-item>
        </a-form>
        <p class="url-hint">
          支持添加网页内容，系统会自动抓取网页文本并进行分块。请确保URL格式正确且可以公开访问。
        </p>
      </div>
    </div>
  </a-modal>

  <div class="db-main-container">
    <a-tabs v-model:activeKey="state.curPage" class="atab-container" type="card">

      <a-tab-pane key="files">
        <template #tab><span><ReadOutlined />文件列表</span></template>
        <div class="db-tab-container">
          <div class="actions" style="display: flex; gap: 10px; justify-content: space-between;">
            <div class="left-actions" style="display: flex; gap: 10px;">
              <a-button type="primary" @click="showAddFilesModal" :loading="state.refrashing" :icon="h(PlusOutlined)">添加文件</a-button>
              <a-button @click="handleRefresh" :loading="state.refrashing">刷新</a-button>
            </div>
            <div class="batch-actions" style="display: flex; gap: 10px;" v-if="selectedRowKeys.length > 0">
              <span style="margin-right: 8px;">已选择 {{ selectedRowKeys.length }} 项</span>
              <a-button
                type="primary"
                @click="handleBatchIndex"
                :loading="state.batchIndexing"
                :disabled="!hasSelectedPendingFiles"
              >
                批量索引
              </a-button>
              <a-button
                type="primary"
                danger
                @click="handleBatchDelete"
                :loading="state.batchDeleting"
                :disabled="!canBatchDelete"
              >
                批量删除
              </a-button>
            </div>
          </div>

          <a-table
            :columns="columns"
            :data-source="Object.values(database.files || {})"
            row-key="file_id"
            class="my-table"
            size="small"
            bordered
            :pagination="pagination"
            :row-selection="{
              selectedRowKeys: selectedRowKeys,
              onChange: onSelectChange,
              getCheckboxProps: getCheckboxProps
            }">
            <template #bodyCell="{ column, text, record }">
              <a-tooltip v-if="column.key === 'filename'" :title="record.file_id" placement="left">
                <a-button class="main-btn" type="link" @click="openFileDetail(record)">{{ text }}</a-button>
              </a-tooltip>
              <span v-else-if="column.key === 'type'" :class="['span-type', text]">{{ text?.toUpperCase() }}</span>
              <CheckCircleFilled v-else-if="column.key === 'status' && text === 'done'" style="color: #41A317;"/>
              <CloseCircleFilled v-else-if="column.key === 'status' && text === 'failed'" style="color: #FF4D4F ;"/>
              <HourglassFilled v-else-if="column.key === 'status' && text === 'processing'" style="color: #1677FF;"/>
              <ClockCircleFilled v-else-if="column.key === 'status' && text === 'waiting'" style="color: #FFCD43;"/>
              <HddOutlined v-else-if="column.key === 'status' && text === 'pending_indexing'" style="color: #FFCD43;"/>

              <a-tooltip v-else-if="column.key === 'created_at'" :title="record.status" placement="left">
                <span>{{ formatRelativeTime(Math.round(text*1000)) }}</span>
              </a-tooltip>

              <div v-else-if="column.key === 'action'" style="display: flex; gap: 10px;">
                <a-button
                  v-if="record.status === 'pending_indexing' || record.status === 'failed'"
                  type="link"
                  @click="handleIndexFile(record.file_id)"
                  :loading="state.indexingFile === record.file_id"
                  :disabled="state.lock || state.indexingFile === record.file_id"
                >
                  索引
                </a-button>
                <a-button class="del-btn" type="link"
                  @click="handleDeleteFile(record.file_id)"
                  :disabled="state.lock || record.status === 'processing' || record.status === 'waiting' || state.indexingFile === record.file_id"
                  >
                  删除
                </a-button>
              </div>
              <span v-else>{{ text }}</span>
            </template>
          </a-table>
          <a-modal
            v-model:open="state.fileDetailModalVisible"
            class="custom-class"
            :title="selectedFile?.filename || '文件详情'"
            width="1000px"
            @after-open="afterOpenChange"
            :footer="null"
          >
            <template v-if="state.fileDetailLoading">
              <div class="loading-container">
                <a-spin tip="加载中..." />
              </div>
            </template>
            <template v-else>
              <h3>共 {{ selectedFile?.lines?.length || 0 }} 个片段</h3>
              <div class="file-detail-content">
                <p v-for="line in selectedFile?.lines || []" :key="line.id" class="line-text">
                  {{ line.text }}
                </p>
              </div>
            </template>
          </a-modal>
        </div>
      </a-tab-pane>

      <a-tab-pane key="query-test" force-render>
        <template #tab><span><SearchOutlined />检索测试</span></template>
        <div class="query-test-container db-tab-container">
          <div class="sider">
            <div class="sider-top">
              <div class="query-params" v-if="state.curPage == 'query-test'">
                <!-- <h3 class="params-title">查询参数</h3> -->
                <div class="params-group">
                  <div class="params-item">
                    <p>检索数量：</p>
                    <a-input-number size="small" v-model:value="meta.maxQueryCount" :min="1" :max="20" />
                  </div>
                  <div class="params-item">
                    <p>过滤低质量：</p>
                    <a-switch v-model:checked="meta.filter" />
                  </div>
                  <div class="params-item">
                    <p>筛选 TopK：</p>
                    <a-input-number size="small" v-model:value="meta.topK" :min="1" :max="meta.maxQueryCount" />
                  </div>
                  <div class="params-item" v-if="configStore.config.enable_reranker">
                    <p>排序方式：</p>
                    <a-radio-group v-model:value="meta.sortBy" button-style="solid" size="small">
                      <a-radio-button value="rerank_score">重排序分</a-radio-button>
                      <a-radio-button value="distance">相似度</a-radio-button>
                    </a-radio-group>
                  </div>
                </div>
                <div class="params-group">
                  <div class="params-item w100" v-if="configStore.config.enable_reranker">
                    <p>重排序阈值：</p>
                    <a-slider v-model:value="meta.rerankThreshold" :min="0" :max="1" :step="0.01" />
                  </div>
                  <div class="params-item w100">
                    <p>距离阈值：</p>
                    <a-slider v-model:value="meta.distanceThreshold" :min="0" :max="1" :step="0.01" />
                  </div>
                </div>
                <div class="params-group">
                  <div class="params-item col">
                    <p>重写查询<small>（修改后需重新检索）</small>：</p>
                    <a-segmented v-model:value="meta.use_rewrite_query" :options="use_rewrite_queryOptions">
                      <template #label="{ payload }">
                        <div>
                          <p style="margin: 4px 0">{{ payload.subTitle }}</p>
                        </div>
                      </template>
                    </a-segmented>
                  </div>
                </div>
              </div>
            </div>
            <div class="sider-bottom">
            </div>
          </div>
          <div class="query-result-container">
            <div class="query-action">
              <a-textarea
                v-model:value="queryText"
                placeholder="填写需要查询的句子"
                :auto-size="{ minRows: 2, maxRows: 10 }"
              />
              <a-button class="btn-query" @click="onQuery" :disabled="queryText.length == 0">
                <span v-if="!state.searchLoading"><SearchOutlined /> 检索</span>
                <span v-else><LoadingOutlined /></span>
              </a-button>
            </div>

            <!-- 新增示例按钮 -->
            <!-- <div class="query-examples-container">
              <div class="examples-title">示例查询：</div>
              <div class="query-examples">
                <a-button v-for="example in queryExamples" :key="example" @click="useQueryExample(example)">
                  {{ example }}
                </a-button>
              </div>
            </div> -->
            <div class="query-test" v-if="queryResult">
              <div class="results-overview">
                <div class="results-stats">
                  <span class="stat-item">
                    <strong>总数:</strong> {{ queryResult.all_results.length }}
                  </span>
                  <span class="stat-item">
                    <strong>过滤后:</strong> {{ filteredResults.length }}
                  </span>
                  <span class="stat-item">
                    <strong>TopK:</strong> {{ meta.topK }}
                  </span>
                  <span class="stat-item">
                    <strong>排序:</strong> {{ meta.sortBy === 'rerank_score' ? '重排序分' : '相似度' }}
                  </span>
                </div>
                <div class="rewritten-query" v-if="queryResult.rw_query">
                  <strong>重写后查询:</strong>
                  <span class="query-text">{{ queryResult.rw_query }}</span>
                </div>
              </div>
              <div class="query-result-card" v-for="(result, idx) in (filteredResults)" :key="idx">
                <p>
                  <strong>#{{ idx + 1 }}&nbsp;&nbsp;&nbsp;</strong>
                  <span>{{ result.file.filename }}&nbsp;&nbsp;&nbsp;</span>
                  <span><strong>相似度</strong>：{{ result.distance.toFixed(4) }}&nbsp;&nbsp;&nbsp;</span>
                  <span v-if="result.rerank_score"><strong>重排序分</strong>：{{ result.rerank_score.toFixed(4) }}</span>
                </p>
                <p class="query-text">{{ result.entity.text }}</p>
              </div>
            </div>
          </div>
        </div>
      </a-tab-pane>
      <!-- <a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane> -->
    </a-tabs>
  </div>
</div>
</template>

<script setup>
import { onMounted, reactive, ref, watch, toRaw, onUnmounted, computed } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { useRoute, useRouter } from 'vue-router';
import { useConfigStore } from '@/stores/config'
import { useUserStore } from '@/stores/user'
import { knowledgeBaseApi } from '@/apis/admin_api'
import HeaderComponent from '@/components/HeaderComponent.vue';
import {
  ReadOutlined,
  LeftOutlined,
  CheckCircleFilled,
  HourglassFilled,
  CloseCircleFilled,
  ClockCircleFilled,
  DeleteOutlined,
  CloudUploadOutlined,
  SearchOutlined,
  LoadingOutlined,
  FileOutlined,
  LinkOutlined,
  EditOutlined,
  PlusOutlined,
  HddOutlined,
  SettingOutlined,
} from '@ant-design/icons-vue'
import { h } from 'vue';


const route = useRoute();
const router = useRouter();
const databaseId = ref(route.params.database_id);
const database = ref({});

const fileList = ref([]);
const selectedFile = ref(null);

// 查询测试
const queryText = ref('');
const queryResult = ref(null)
const filteredResults = ref([])
const configStore = useConfigStore()

const state = reactive({
  databaseLoading: false,
  adding: false,
  refrashing: false,
  searchLoading: false,
  lock: false,
  fileDetailModalVisible: false,
  fileDetailLoading: false,
  refreshInterval: null,
  curPage: "files",
  indexingFile: null,
  batchIndexing: false,
  batchDeleting: false,
  chunkLoading: false,
});

const meta = reactive({
  mode: 'search',
  maxQueryCount: 30,
  filter: true,
  use_rewrite_query: 'off',
  rerankThreshold: 0.1,
  distanceThreshold: 0.3,
  topK: 10,
  sortBy: 'rerank_score',
});

const enable_ocr_options = ref([
  { value: 'disable', payload: { title: '不启用' } },
  { value: 'onnx_rapid_ocr', payload: { title: 'ONNX with RapidOCR' } },
  { value: 'mineru_ocr', payload: { title: 'MinerU OCR' } },
  { value: 'paddlex_ocr', payload: { title: 'Paddlex OCR' } },
])

const use_rewrite_queryOptions = ref([
  { value: 'off', payload: { title: 'off', subTitle: '不启用' } },
  { value: 'on', payload: { title: 'on', subTitle: '启用重写' } },
  { value: 'hyde', payload: { title: 'hyde', subTitle: '伪文档生成' } },
])

const pagination = ref({
  pageSize: 15,
  current: 1,
  total: computed(() => database.value?.files?.length || 0),
  showSizeChanger: true,
  onChange: (page, pageSize) => pagination.value.current = page,
  showTotal: (total, range) => `共 ${total} 条`,
  onShowSizeChange: (current, pageSize) => pagination.value.pageSize = pageSize,
})

const filterQueryResults = () => {
  if (!queryResult.value || !queryResult.value.all_results) {
    return;
  }

  let results = toRaw(queryResult.value.all_results);
  console.log("results", results);

  if (meta.filter) {
    results = results.filter(r => r.distance >= meta.distanceThreshold);
    console.log("before", results);

    // 根据排序方式决定排序逻辑
    if (configStore.config.enable_reranker) {
      // 先过滤掉低于阈值的结果
      results = results.filter(r => r.rerank_score >= meta.rerankThreshold);

      // 根据选择的排序方式进行排序
      if (meta.sortBy === 'rerank_score') {
        results = results.sort((a, b) => b.rerank_score - a.rerank_score);
      } else {
        // 按距离排序 (数值越大表示越相似)
        results = results.sort((a, b) => b.distance - a.distance);
      }
    } else {
      // 没有启用重排序时，默认按距离排序
      results = results.sort((a, b) => b.distance - a.distance);
    }

    console.log("after", results);

    results = results.slice(0, meta.topK);
  }

  filteredResults.value = results;
}

const onQuery = () => {
  if (database.value.embed_model != configStore.config.embed_model) {
    message.error('向量模型不匹配，请重新选择')
    return
  }

  console.log(queryText.value)
  state.searchLoading = true
  if (!queryText.value.trim()) {
    message.error('请输入查询内容')
    state.searchLoading = false
    return
  }
  meta.db_id = database.value.db_id

  try {
    knowledgeBaseApi.queryTest({
      query: queryText.value.trim(),
      meta: meta
    })
    .then(data => {
      console.log(data)
      queryResult.value = data
      filterQueryResults()
    })
    .catch(error => {
      console.error(error)
      message.error(error.message)
    })
    .finally(() => {
      state.searchLoading = false
    })
  } catch (error) {
    console.error(error)
    message.error(error.message)
    state.searchLoading = false
  }
}

const handleFileUpload = (event) => {
  console.log(event)
  console.log(fileList.value)
}

const handleDrop = (event) => {
  console.log(event)
  console.log(fileList.value)
}

const afterOpenChange = (visible) => {
  if (!visible) {
    selectedFile.value = null
  }
}

const backToDatabase = () => {
  router.push('/database')
}

const handleRefresh = () => {
  state.refrashing = true
  getDatabaseInfo().then(() => {
    state.refrashing = false
    console.log(database.value)
  })
}



const deleteDatabse = () => {
  Modal.confirm({
    title: '删除数据库',
    content: '确定要删除该数据库吗？',
    okText: '确认',
    cancelText: '取消',
    onOk: () => {
      state.lock = true
      knowledgeBaseApi.deleteDatabase(databaseId.value)
        .then(data => {
          console.log(data)
          message.success(data.message || '删除成功')
          router.push('/database')
        })
        .catch(error => {
          console.error(error)
          message.error(error.message || '删除失败')
        })
        .finally(() => {
          state.lock = false
        })
    },
    onCancel: () => {
      console.log('Cancel');
    },
  });
}

const openFileDetail = (record) => {
  // 先打开弹窗
  state.fileDetailModalVisible = true;
  selectedFile.value = {
    ...record,
    lines: []
  };

  // 设置加载状态
  state.fileDetailLoading = true;
  state.lock = true;

  try {
    knowledgeBaseApi.getDocumentDetail(databaseId.value, record.file_id)
      .then(data => {
        console.log(data);
        if (data.status == "failed") {
          message.error(data.message);
          state.fileDetailModalVisible = false;
          return;
        }
        selectedFile.value = {
          ...record,
          lines: data.lines || []
        };
      })
      .catch(error => {
        console.error(error);
        message.error(error.message);
        state.fileDetailModalVisible = false;
      })
      .finally(() => {
        state.fileDetailLoading = false;
        state.lock = false;
      });
  } catch (error) {
    console.error(error);
    message.error('获取文件详情失败!!!!');
    state.fileDetailLoading = false;
    state.lock = false;
    state.fileDetailModalVisible = false;
  }
}

const formatRelativeTime = (timestamp, offset = 0) => {
    // 如果调整为东八区时间（UTC+8），则offset为8，否则为0
    const timezoneOffset = offset * 60 * 60 * 1000; // 东八区偏移量（毫秒）
    const adjustedTimestamp = timestamp + timezoneOffset;

    const now = Date.now();
    const secondsPast = (now - adjustedTimestamp) / 1000;

    if (secondsPast < 60) {
        return Math.round(secondsPast) + ' 秒前';
    } else if (secondsPast < 3600) {
        return Math.round(secondsPast / 60) + ' 分钟前';
    } else if (secondsPast < 86400) {
        return Math.round(secondsPast / 3600) + ' 小时前';
    } else {
        const date = new Date(adjustedTimestamp);
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        return `${year} 年 ${month} 月 ${day} 日`;
    }
}


const getDatabaseInfo = () => {
  const db_id = databaseId.value
  if (!db_id) {
    return
  }
  state.lock = true
  state.databaseLoading = true
  return new Promise((resolve, reject) => {
    knowledgeBaseApi.getDatabaseInfo(db_id)
      .then(data => {
        database.value = data
        resolve(data)
      })
      .catch(error => {
        console.error(error)
        message.error(error.message || '获取数据库信息失败')
        reject(error)
      })
      .finally(() => {
        state.lock = false
        state.databaseLoading = false
      })
  })
}

const deleteFile = (fileId) => {
  state.lock = true
  console.debug("deleteFile", databaseId.value, fileId)
  knowledgeBaseApi.deleteFile(databaseId.value, fileId)
    .then(data => {
      console.log(data)
      message.success(data.message || '删除成功')
      getDatabaseInfo()
    })
    .catch(error => {
      console.error(error)
      message.error(error.message || '删除失败')
    })
    .finally(() => {
      state.lock = false
    })
}


const handleDeleteFile = (fileId) => {
  console.log(fileId)
  //删除提示
  Modal.confirm({
    title: '删除文件',
    content: '确定要删除该文件吗？',
    okText: '确认',
    cancelText: '取消',
    onOk: () => deleteFile(fileId),
    onCancel: () => {
      console.log('Cancel');
    },
  });
}


// 批量删除处理函数
const handleBatchDelete = () => {
  if (!canBatchDelete.value) {
    message.info('没有可删除的文件');
    return;
  }

  const files = database.value.files || {};
  const fileCount = selectedRowKeys.value.length;

  Modal.confirm({
    title: '批量删除文件',
    content: `确定要删除选中的 ${fileCount} 个文件吗？`,
    okText: '确认',
    cancelText: '取消',
    onOk: async () => {
      state.batchDeleting = true;
      try {
        const promises = selectedRowKeys.value
          .filter(fileId => {
            const file = files[fileId];
            return !(file.status === 'processing' || file.status === 'waiting');
          })
          .map(fileId =>
            deleteFile(fileId)
          );

        const results = await Promise.allSettled(promises);

        const succeeded = results.filter(r => r.status === 'fulfilled').length;
        const failed = results.filter(r => r.status === 'rejected').length;

        if (succeeded > 0) {
          message.success(`成功删除 ${succeeded} 个文件`);
        }
        if (failed > 0) {
          message.error(`${failed} 个文件删除失败`);
        }

        selectedRowKeys.value = []; // 清空选择
        getDatabaseInfo(); // 刷新列表状态
      } catch (error) {
        console.error('批量删除出错:', error);
        message.error('批量删除过程中发生错误');
      } finally {
        state.batchDeleting = false;
      }
    },
  });
};

const chunkParams = ref({
  chunk_size: 1000,
  chunk_overlap: 200,
  enable_ocr: 'disable',
  auto_indexing: false,
})

const chunkResults = ref([]);
const activeFileKeys = ref([]);

// 获取所有分块的总数
const getTotalChunks = () => {
  return chunkResults.value.reduce((total, file) => total + file.nodes.length, 0);
}

// "生成分块" - 修改后的逻辑
const chunkFiles = () => {
  console.log(fileList.value)
  const files = fileList.value.filter(file => file.status === 'done').map(file => file.response.file_path)
  console.log(files)

  if (files.length === 0) {
    message.error('请先上传文件')
    return
  }

  state.chunkLoading = true

  knowledgeBaseApi.fileToChunk({
    db_id: databaseId.value, // 添加 db_id
    files: files,
    params: chunkParams.value
  })
  .then(data => {
    console.log('文件处理结果:', data)
    if (data.status === 'success') {
      const autoIndexingInfo = chunkParams.value.auto_indexing ? '，自动索引已启动' : '，请手动点击索引按钮完成索引';
      message.info(data.message + autoIndexingInfo || '文件已提交处理，请稍后在列表刷新查看状态');
      fileList.value = []; // 清空已上传文件列表
      addFilesModalVisible.value = false; // 关闭弹窗
      getDatabaseInfo(); // 刷新数据库信息以显示新文件及其状态
    } else {
      message.error(data.message || '文件处理失败');
    }
  })
  .catch(error => {
    console.error(error)
    message.error(error.message || '文件处理请求失败')
  })
  .finally(() => {
    state.chunkLoading = false
  })
}

// "生成分块" - 修改后的逻辑
const chunkUrls = () => {
  const urls = urlList.value.split('\n')
    .map(url => url.trim())
    .filter(url => url.length > 0 && (url.startsWith('http://') || url.startsWith('https://')));

  if (urls.length === 0) {
    message.error('请输入有效的网页链接（必须以http://或https://开头）');
    return;
  }

  state.chunkLoading = true;

  knowledgeBaseApi.urlToChunk({
    db_id: databaseId.value, // 添加 db_id
    urls: urls,
    params: chunkParams.value
  })
  .then(data => {
    console.log('URL处理结果:', data);
    if (data.status === 'success') {
      const autoIndexingInfo = chunkParams.value.auto_indexing ? '，自动索引已启动' : '，请手动点击索引按钮完成索引';
      message.success(data.message + autoIndexingInfo || 'URL已提交处理，请稍后在列表刷新查看状态');
      urlList.value = ''; // 清空URL输入
      addFilesModalVisible.value = false; // 关闭弹窗
      getDatabaseInfo(); // 刷新数据库信息以显示新文件及其状态
    } else {
      message.error(data.message || 'URL处理失败');
    }
  })
  .catch(error => {
    console.error(error);
    message.error(error.message || '处理URL请求失败');
  })
  .finally(() => {
    state.chunkLoading = false;
  });
};

const columns = [
  // { title: '文件ID', dataIndex: 'file_id', key: 'file_id' },
  { title: '文件名', dataIndex: 'filename', key: 'filename', ellipsis: true },
  { title: '上传时间', dataIndex: 'created_at', key: 'created_at', width: 150 },
  { title: '状态', dataIndex: 'status', key: 'status', width: 80 },
  { title: '类型', dataIndex: 'type', key: 'type', width: 80 },
  { title: '操作', key: 'action', dataIndex: 'file_id', width: 150 }
];

watch(() => route.params.database_id, (newId) => {
    databaseId.value = newId;
    console.log(newId)
    clearInterval(state.refreshInterval)
    getDatabaseInfo()
  }
);

// 检测到 meta 变化时重新查询
watch(() => meta, () => {
  filterQueryResults()
}, { deep: true })

// 添加更多示例查询
const queryExamples = ref([
  '贾宝玉的丫鬟有哪些？',
  '请介绍一下红楼梦的主要人物',
  '林黛玉是什么性格？',
  '曹雪芹的创作背景',
]);

// 使用示例查询的方法
const useQueryExample = (example) => {
  queryText.value = example;
  onQuery();
};

onMounted(() => {
  getDatabaseInfo();
  state.refreshInterval = setInterval(() => {
    getDatabaseInfo();
  }, 1000);
})

// 添加 onUnmounted 钩子，在组件卸载时清除定时器
onUnmounted(() => {
  if (state.refreshInterval) {
    clearInterval(state.refreshInterval);
    state.refreshInterval = null;
  }
})

const uploadMode = ref('file');
const urlList = ref('');

const chunkData = () => {
  if (uploadMode.value === 'file') {
    chunkFiles();
  } else if (uploadMode.value === 'url') {
    chunkUrls();
  }
}

const getAuthHeaders = () => {
  const userStore = useUserStore();
  return userStore.getAuthHeaders();
};

// 编辑知识库表单
const editModalVisible = ref(false);
const editFormRef = ref(null);
const editForm = reactive({
  name: '',
  description: ''
});

const rules = {
  name: [{ required: true, message: '请输入知识库名称' }]
};

// 分块参数配置弹窗
const chunkConfigModalVisible = ref(false);
const tempChunkParams = ref({
  chunk_size: 1000,
  chunk_overlap: 200,
  auto_indexing: false,
});

// 添加文件弹窗
const addFilesModalVisible = ref(false);

// 显示编辑对话框
const showEditModal = () => {
  editForm.name = database.value.name || '';
  editForm.description = database.value.description || '';
  editModalVisible.value = true;
};

// 提交编辑表单
const handleEditSubmit = () => {
  editFormRef.value.validate().then(() => {
    updateDatabaseInfo();
  }).catch(err => {
    console.error('表单验证失败:', err);
  });
};

// 更新知识库信息
const updateDatabaseInfo = async () => {
  try {
    state.lock = true;
    const response = await knowledgeBaseApi.updateDatabaseInfo(databaseId.value, {
      name: editForm.name,
      description: editForm.description
    });

    message.success('知识库信息更新成功');
    editModalVisible.value = false;
    await getDatabaseInfo(); // 刷新数据
  } catch (error) {
    console.error(error);
    message.error(error.message || '更新失败');
  } finally {
    state.lock = false;
  }
};

// 显示分块参数配置弹窗
const showChunkConfigModal = () => {
  tempChunkParams.value = {
    chunk_size: chunkParams.value.chunk_size,
    chunk_overlap: chunkParams.value.chunk_overlap,
    auto_indexing: chunkParams.value.auto_indexing,
  };
  chunkConfigModalVisible.value = true;
};

// 处理分块参数配置提交
const handleChunkConfigSubmit = () => {
  chunkParams.value.chunk_size = tempChunkParams.value.chunk_size;
  chunkParams.value.chunk_overlap = tempChunkParams.value.chunk_overlap;
  chunkParams.value.auto_indexing = tempChunkParams.value.auto_indexing;
  chunkConfigModalVisible.value = false;
  message.success('分块参数配置已更新');
};

// 显示添加文件弹窗
const showAddFilesModal = () => {
  addFilesModalVisible.value = true;
};

const handleIndexFile = (fileId) => {
  if (!fileId) {
    message.error('无效的文件ID');
    return;
  }
  state.lock = true;
  knowledgeBaseApi.indexFile({
    db_id: databaseId.value,
    file_id: fileId
  })
  .then(response => {
    if (response.status === 'success') {
      message.success(response.message || `文件 ${fileId} 已开始索引。`);
      getDatabaseInfo(); // Refresh to update status
    } else {
      message.error(response.message || `文件 ${fileId} 索引启动失败。`);
    }
  })
  .catch(error => {
    console.error(`索引文件 ${fileId} 失败:`, error);
    message.error(error.message || `索引文件 ${fileId} 时发生错误。`);
  })
  .finally(() => {
    state.indexingFile = null; // Reset loading state for this file
    state.lock = false;
  });
};

// 计算是否有待索引的文件
const hasPendingFiles = computed(() => {
  return Object.values(database.value.files || {}).some(file => file.status === 'pending_indexing');
});

// 选中的行
const selectedRowKeys = ref([]);

// 行选择改变处理
const onSelectChange = (keys) => {
  selectedRowKeys.value = keys;
};

// 获取复选框属性
const getCheckboxProps = (record) => ({
  disabled: state.lock || record.status === 'processing' || record.status === 'waiting' || state.indexingFile === record.file_id,
});

// 计算是否有选中的待索引文件
const hasSelectedPendingFiles = computed(() => {
  const files = database.value.files || {};
  return selectedRowKeys.value.some(key => files[key]?.status === 'pending_indexing');
});

// 计算是否可以批量删除
const canBatchDelete = computed(() => {
  const files = database.value.files || {};
  return selectedRowKeys.value.some(key => {
    const file = files[key];
    return !(state.lock || file.status === 'processing' || file.status === 'waiting' || state.indexingFile === file.file_id);
  });
});

// 批量索引处理函数
const handleBatchIndex = async () => {
  if (!hasSelectedPendingFiles.value) {
    message.info('没有需要索引的文件');
    return;
  }

  state.batchIndexing = true;
  const files = database.value.files || {};
  const pendingFiles = selectedRowKeys.value
    .filter(key => files[key]?.status === 'pending_indexing');

  try {
    const promises = pendingFiles.map(fileId =>
      knowledgeBaseApi.indexFile({
        db_id: databaseId.value,
        file_id: fileId
      })
    );

    const results = await Promise.allSettled(promises);

    const succeeded = results.filter(r => r.status === 'fulfilled' && r.value.status === 'success').length;
    const failed = results.filter(r => r.status === 'rejected' || (r.status === 'fulfilled' && r.value.status !== 'success')).length;

    if (succeeded > 0) {
      message.success(`成功提交 ${succeeded} 个文件进行索引`);
    }
    if (failed > 0) {
      message.error(`${failed} 个文件提交索引失败`);
    }

    selectedRowKeys.value = []; // 清空选择
    getDatabaseInfo(); // 刷新列表状态
  } catch (error) {
    console.error('批量索引出错:', error);
    message.error('批量索引过程中发生错误');
  } finally {
    state.batchIndexing = false;
  }
};


</script>

<style lang="less" scoped>
.database-info {
  margin: 8px 0 0;
}

.db-main-container {
  display: flex;
  width: 100%;
}

.db-tab-container {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.query-test-container {
  display: flex;
  flex-direction: row;
  gap: 20px;

  .sider {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 325px;
    height: 100%;
    padding: 0;
    flex: 0 0 325px;

    .sider-top {
      .query-params {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        font-size: 15px;
        gap: 12px;
        padding-top: 12px;
        padding-right: 16px;
        border: 1px solid var(--main-light-3);
        background-color: var(--main-light-6);
        border-radius: 8px;
        padding: 16px;
        margin-right: 8px;

        .params-title {
          margin-top: 0;
          margin-bottom: 16px;
          color: var(--main-color);
          font-size: 18px;
          text-align: center;
          font-weight: bold;
        }

        .params-group {
          margin-bottom: 16px;
          padding-bottom: 16px;
          border-bottom: 1px solid var(--main-light-3);

          &:last-child {
            margin-bottom: 0;
            padding-bottom: 0;
            border-bottom: none;
          }
        }

        .params-item {
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 12px;
          margin-bottom: 12px;

          &:last-child {
            margin-bottom: 0;
          }

          p {
            margin: 0;
            color: var(--gray-900);
          }

          &.col {
            align-items: flex-start;
            flex-direction: column;
            width: 100%;
            height: auto;
          }

          &.w100,
          &.col {
            & > * {
              width: 100%;
            }
          }
        }

        .ant-slider {
          margin: 6px 0px;
        }
      }
    }
  }

  .query-result-container {
    flex: 1;
    padding-bottom: 20px;
  }

  .query-action {
    display: flex;
    gap: 8px;
    margin-bottom: 20px;

    textarea {
      padding: 12px 16px;
      border: 1px solid var(--main-light-2);
    }

    button.btn-query {
      height: auto;
      width: 100px;
      box-shadow: none;
      border: none;
      font-weight: bold;
      background: var(--main-light-3);
      color: var(--main-color);

      &:disabled {
        cursor: not-allowed;
        background: var(--main-light-4);
        color: var(--gray-700);
      }
    }
  }

  .query-examples-container {
    margin-bottom: 20px;
    padding: 12px;
    background: var(--main-light-6);
    border-radius: 8px;
    border: 1px solid var(--main-light-3);

    .examples-title {
      font-weight: bold;
      margin-bottom: 10px;
      color: var(--main-color);
    }

    .query-examples {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin: 10px 0 0;

      .ant-btn {
        font-size: 14px;
        padding: 4px 12px;
        height: auto;
        background-color: var(--gray-200);
        border: none;
        color: var(--gray-800);

        &:hover {
          color: var(--main-color);
        }
      }
    }
  }

  .query-test {
    display: flex;
    flex-direction: column;
    border-radius: 12px;
    gap: 20px;

    .results-overview {
      background-color: #fff;
      border-radius: 8px;
      padding: 16px;
      border: 1px solid var(--main-light-3);

      .results-stats {
        display: flex;
        justify-content: flex-start;

        .stat-item {
          border-radius: 4px;
          font-size: 14px;
          margin-right: 24px;
          padding: 4px 8px;
          strong {
            color: var(--main-color);
            margin-right: 4px;
          }
        }
      }

      .rewritten-query {
        border-radius: 4px;
        font-size: 14px;
        padding: 4px 8px;
        strong {
          color: var(--main-color);
          margin-right: 8px;
        }

        .query-text {
          font-style: italic;
          color: var(--gray-900);
        }
      }
    }

    .query-result-card {
      padding: 20px;
      border-radius: 8px;
      background: #fff;
      border: 1px solid var(--main-light-3);
      transition: box-shadow 0.3s ease;

      &:hover {
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
      }

      p {
        margin-bottom: 8px;
        line-height: 1.6;
        color: var(--gray-900);

        &:last-child {
          margin-bottom: 0;
        }
      }

      strong {
        color: var(--main-color);
      }

      .query-text {
        font-size: 15px;
        margin-top: 12px;
        padding-top: 12px;
        border-top: 1px solid var(--main-light-3);
      }
    }
  }
}



.my-table {
  button.ant-btn-link {
    padding: 0;
  }

  .span-type {
    color: white;
    padding: 2px 4px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: bold;
    opacity: 0.8;
    user-select: none;
    background: #005F77;
  }

  .pdf {
    background: #005F77;
  }

  .txt {
    background: #068033;
  }

  .docx, .doc {
    background: #2C59B7;
  }

  .md {
    background: #020817;
  }



  button.main-btn {
    font-weight: bold;
    font-size: 14px;
    color: var(--gray-800);
    &:hover {
      cursor: pointer;
      color: var(--main-color);
      font-weight: bold;
    }
  }

  button.del-btn {
    cursor: pointer;

    &:hover {
      color: var(--error-color);
    }
    &:disabled {
      cursor: not-allowed;
    }
  }
}

.file-detail-content {
  max-height: 60vh;
  overflow-y: auto;
  // padding: 0 10px;
}

.custom-class .line-text {
  padding: 10px;
  border-radius: 4px;
  margin: 8px 0;
  background-color: var(--gray-100);

  &:hover {
    background-color: var(--main-light-4);
  }
}

.add-files-content {
  .upload-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    gap: 20px;

    .source-selector {
      display: flex;
      gap: 10px;

      .upload-mode-selector {
        cursor: pointer;
        padding: 4px 16px;
        border-radius: 8px;
        background-color: var(--main-light-4);
        border: 1px solid var(--main-light-3);
        transition: all 0.2s ease;
        &.active {
          color: var(--main-color);
          background-color: var(--main-10);
          border-color: var(--main-color);
        }
      }
    }

    .config-controls {
      .ant-btn {
        border-color: var(--main-light-3);
        color: var(--gray-700);
        &:hover {
          border-color: var(--main-color);
          color: var(--main-color);
        }
      }
    }
  }

  .ocr-config {
    margin-bottom: 16px;
    padding: 12px 16px;
    background-color: var(--main-light-6);
    border-radius: 8px;
    border: 1px solid var(--main-light-3);

    .ant-form-item {
      margin-bottom: 0;

      .ant-form-item-label {
        color: var(--gray-800);
        font-weight: 500;
      }
    }

    .param-description {
      color: var(--gray-600);
      font-size: 12px;
      margin-left: 12px;
    }
  }

  .upload {
    margin-bottom: 20px;
    .upload-dragger {
      margin: 0px;
      min-height: 200px;
    }
  }

  .url-input {
    margin-bottom: 20px;

    .ant-textarea {
      border-color: var(--main-light-3);
      background-color: #fff;
      font-family: monospace;
      resize: vertical;
    }

    .ant-textarea:hover,
    .ant-textarea:focus {
      border-color: var(--main-color);
    }

    .url-hint {
      font-size: 13px;
      color: var(--gray-600);
      margin-top: 5px;
      line-height: 1.5;
    }
  }
}

.chunk-config-content {
  .params-info {
    background-color: var(--main-light-4);
    border-radius: 6px;
    padding: 10px 12px;
    margin-bottom: 16px;

    p {
      margin: 0;
      font-size: 13px;
      line-height: 1.5;
      color: var(--gray-700);
    }
  }

  .ant-form-item {
    margin-bottom: 16px;

    .ant-form-item-label {
      padding-bottom: 6px;

      label {
        color: var(--gray-800);
        font-weight: 500;
        font-size: 15px;
      }
    }
  }

  .ant-input-number {
    border-radius: 6px;

    &:hover, &:focus {
      border-color: var(--main-color);
    }
  }

  .param-description {
    color: var(--gray-600);
    font-size: 12px;
    margin-top: 4px;
    margin-bottom: 0;
  }
}

.chunk-preview {
  margin-top: 20px;

  .preview-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;

    h3 {
      margin: 0;
      color: var(--main-color);
      font-size: 18px;
    }
  }

  .result-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(600px, 1fr));
    gap: 12px;
    margin-top: 10px;
  }

  .chunk {
    background-color: var(--main-light-5);
    border: 1px solid var(--main-light-3);
    border-radius: 8px;
    padding: 16px;
    word-wrap: break-word;
    word-break: break-all;
    transition: all 0.2s ease;

    &:hover {
      background-color: var(--main-light-4);
      border-color: var(--main-light-2);
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
    }

    p {
      margin: 0;
      line-height: 1.6;

      strong {
        color: var(--main-color);
        margin-right: 6px;
      }
    }
  }
}

.url-input {
  margin-bottom: 20px;
}



.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 200px;
}

.ant-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
</style>

<style lang="less">
.atab-container {
  padding: 0;
  width: 100%;
  max-height: 100%;
  overflow: auto;

  div.ant-tabs-nav {
    background: var(--main-light-5);
    padding: 8px 20px;
    padding-bottom: 0;
  }

  .ant-tabs-content-holder {
    padding: 0 20px;
  }
}

.params-item.col .ant-segmented {
  width: 100%;

  div.ant-segmented-group {
    display: flex;
    justify-content: space-around;
  }
}

</style>

<style lang="less">
.db-main-container {
  .atab-container {
    padding: 0;
    width: 100%;
    max-height: 100%;
    overflow: auto;

    div.ant-tabs-nav {
      background: var(--main-light-5);
      padding: 8px 20px;
      padding-bottom: 0;
    }

    .ant-tabs-content-holder {
      padding: 0 20px;
    }
  }

  .params-item.col .ant-segmented {
    width: 100%;
    font-size: smaller;
    div.ant-segmented-group {
      display: flex;
      justify-content: space-around;
    }
    label.ant-segmented-item {
      flex: 1;
      text-align: center;
      div.ant-segmented-item-label > div > p {
        font-size: small;
      }
    }
  }
}


</style>

