<script setup lang="ts">
import { Operation, Search, UploadFilled } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, onMounted, reactive, ref } from 'vue';
import { useRoute } from 'vue-router';

import {
  chunkRagDocuments,
  deleteRagDocument,
  getRagDocumentById,
  parseRagDocuments,
  queryRagDocuments,
  saveRagDocument,
  RAG_CHUNK_STRATEGY,
  type RagChunkStrategy,
  type RagDocument,
} from '@/api/ragDocuments';
import { queryRagStores, type RagStore } from '@/api/ragStores';
import RagChunkTaskBoard from '@/components/rag/chunk/RagChunkTaskBoard.vue';
import RagDocumentBatchUploadDialog from '@/components/rag/RagDocumentBatchUploadDialog.vue';
import RagFlowOverview from '@/components/rag/document/RagFlowOverview.vue';

const loading = ref(false);
const submitting = ref(false);
const parseSubmitting = ref(false);
const retryParsing = ref(false);
const route = useRoute();

const storeOptions = ref<RagStore[]>([]);
const docRows = ref<RagDocument[]>([]);

const queryForm = reactive({
  storeId: '',
  parseStatus: '',
  indexStatus: '',
  enabled: '' as string,
  keyword: '',
});

const editDialogVisible = ref(false);
const uploadDialogVisible = ref(false);
const chunkDialogVisible = ref(false);
const selectedDocuments = ref<RagDocument[]>([]);

const editForm = reactive({
  id: '',
  storeId: '',
  attachmentId: '',
  documentTitle: '',
  documentSummary: '',
  enabled: true,
  remark: '',
});

const chunkForm = reactive({
  documentIds: [] as string[],
  chunkStrategy: RAG_CHUNK_STRATEGY.FIXED_LENGTH as RagChunkStrategy,
  chunkSize: 800,
  chunkOverlap: 120,
  delimiter: '。',
});

const chunkStrategyOptions: Array<{ label: string; value: RagChunkStrategy; description: string }> = [
  { label: '固定长度切片', value: RAG_CHUNK_STRATEGY.FIXED_LENGTH, description: '按指定长度和重叠长度切分通用文本' },
  { label: '按段落切片', value: RAG_CHUNK_STRATEGY.PARAGRAPH, description: '按空行、自然段落边界切分' },
  { label: '按标题层级切片', value: RAG_CHUNK_STRATEGY.HEADING, description: '按标题和章节层级组织内容' },
  { label: '按表格行切片', value: RAG_CHUNK_STRATEGY.TABLE_ROW, description: '适合 Excel 表格和结构化明细数据' },
  { label: '按分隔符切片', value: RAG_CHUNK_STRATEGY.DELIMITER, description: '按句号、换行符或自定义分隔符切分' },
  { label: '语义切片', value: RAG_CHUNK_STRATEGY.SEMANTIC, description: '后续结合语义边界或模型能力切分' },
];

const filteredRows = computed(() => {
  const kw = queryForm.keyword.trim().toLowerCase();
  return docRows.value.filter(
    (row) => {
      const matchStore = !queryForm.storeId || row.storeId === queryForm.storeId;
      const matchParseStatus = !queryForm.parseStatus || row.parseStatus === queryForm.parseStatus;
      const matchIndexStatus = !queryForm.indexStatus || row.indexStatus === queryForm.indexStatus;
      const matchEnabled = !queryForm.enabled || String(row.enabled ?? false) === queryForm.enabled;
      const matchKeyword =
        !kw ||
        (row.documentTitle && row.documentTitle.toLowerCase().includes(kw)) ||
        (row.documentSummary && row.documentSummary.toLowerCase().includes(kw)) ||
        (row.remark && row.remark.toLowerCase().includes(kw));
      return matchStore && matchParseStatus && matchIndexStatus && matchEnabled && matchKeyword;
    },
  );
});

const parsedCount = computed(() => docRows.value.filter((row) => row.parseStatus === 'PARSED').length);
const failedCount = computed(() => docRows.value.filter((row) => row.parseStatus === 'FAILED').length);
const selectedParsedCount = computed(() => selectedDocuments.value.filter((row) => row.parseStatus === 'PARSED').length);
const selectedFailedCount = computed(() => selectedDocuments.value.filter((row) => row.parseStatus === 'FAILED').length);

async function loadStores() {
  try {
    const response = await queryRagStores();
    storeOptions.value = response.data ?? [];
  } catch {
    storeOptions.value = [];
  }
}

async function loadDocs() {
  loading.value = true;
  try {
    const response = await queryRagDocuments({
      ...(queryForm.storeId ? { storeId: queryForm.storeId } : {}),
      ...(queryForm.parseStatus ? { parseStatus: queryForm.parseStatus } : {}),
      ...(queryForm.indexStatus ? { indexStatus: queryForm.indexStatus } : {}),
      ...(queryForm.enabled ? { enabled: queryForm.enabled === 'true' } : {}),
    });
    docRows.value = response.data ?? [];
  } finally {
    loading.value = false;
  }
}

function handleSearch() {
  loadDocs();
}

function handleReset() {
  queryForm.storeId = '';
  queryForm.parseStatus = '';
  queryForm.indexStatus = '';
  queryForm.enabled = '';
  queryForm.keyword = '';
  loadDocs();
}

function openUploadDialog() {
  if (storeOptions.value.length === 0) {
    ElMessage.warning('请先创建知识库');
    return;
  }
  uploadDialogVisible.value = true;
}

function handleSelectionChange(rows: RagDocument[]) {
  selectedDocuments.value = rows;
}

function openChunkDialog(rows: RagDocument[]) {
  const parsedRows = rows.filter((row) => row.parseStatus === 'PARSED');
  const ids = parsedRows.map((row) => String(row.id ?? '')).filter(Boolean);
  if (ids.length === 0) {
    ElMessage.warning('请选择解析完成（PARSED）的文档进行切片');
    return;
  }
  if (parsedRows.length < rows.length) {
    ElMessage.warning(`已自动跳过 ${rows.length - parsedRows.length} 个未解析完成文档`);
  }
  chunkForm.documentIds = ids;
  chunkForm.chunkStrategy = RAG_CHUNK_STRATEGY.FIXED_LENGTH;
  chunkForm.chunkSize = 800;
  chunkForm.chunkOverlap = 120;
  chunkForm.delimiter = '。';
  chunkDialogVisible.value = true;
}

function openBatchChunkDialog() {
  openChunkDialog(selectedDocuments.value);
}

async function openEditDialog(row: RagDocument) {
  const detail = row.id ? (await getRagDocumentById(String(row.id))).data : row;

  editForm.id = String(detail.id ?? '');
  editForm.storeId = detail.storeId;
  editForm.attachmentId = detail.attachmentId ?? '';
  editForm.documentTitle = detail.documentTitle ?? '';
  editForm.documentSummary = detail.documentSummary ?? '';
  editForm.enabled = detail.enabled ?? true;
  editForm.remark = detail.remark ?? '';
  editDialogVisible.value = true;
}

async function submitEdit() {
  if (!editForm.id || !editForm.storeId || !editForm.documentTitle) {
    ElMessage.warning('请填写文档标题');
    return;
  }

  submitting.value = true;
  try {
    await saveRagDocument({
      id: editForm.id,
      storeId: editForm.storeId,
      attachmentId: editForm.attachmentId || undefined,
      documentTitle: editForm.documentTitle,
      documentSummary: editForm.documentSummary || undefined,
      enabled: editForm.enabled,
      remark: editForm.remark || undefined,
    });
    editDialogVisible.value = false;
    ElMessage.success('文档信息已更新');
    await loadDocs();
  } finally {
    submitting.value = false;
  }
}

async function removeDoc(row: RagDocument) {
  if (!row.id) return;

  await ElMessageBox.confirm(
    `确认删除文档「${row.documentTitle || '未命名'}」？`,
    '删除确认',
    { type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' },
  );

  await deleteRagDocument(String(row.id));
  ElMessage.success('文档已删除');
  await loadDocs();
}

function toggleEnabled(row: RagDocument) {
  if (!row.id) return;
  const newEnabled = !row.enabled;
  saveRagDocument({
    id: String(row.id),
    storeId: row.storeId,
    documentTitle: row.documentTitle ?? '',
    enabled: newEnabled,
  }).then(() => {
    row.enabled = newEnabled;
    ElMessage.success(`已${newEnabled ? '启用' : '停用'}`);
  });
}

async function submitChunk() {
  if (chunkForm.documentIds.length === 0) {
    ElMessage.warning('请选择需要切片的文档');
    return;
  }
  parseSubmitting.value = true;
  try {
    await chunkRagDocuments({
      documentIds: chunkForm.documentIds,
      chunkStrategy: chunkForm.chunkStrategy,
      chunkSize: chunkForm.chunkSize,
      chunkOverlap: chunkForm.chunkOverlap,
      delimiter: chunkForm.delimiter,
    });
    chunkDialogVisible.value = false;
    ElMessage.success('切片任务已提交');
    await loadDocs();
  } finally {
    parseSubmitting.value = false;
  }
}

async function retryParseRows(rows: RagDocument[]) {
  const ids = rows
    .filter((row) => row.parseStatus === 'FAILED')
    .map((row) => String(row.id ?? ''))
    .filter(Boolean);
  if (ids.length === 0) {
    ElMessage.warning('请选择解析失败（FAILED）的文档重试解析');
    return;
  }
  retryParsing.value = true;
  try {
    await parseRagDocuments({ documentIds: ids });
    ElMessage.success('已提交解析重试任务');
    await loadDocs();
  } finally {
    retryParsing.value = false;
  }
}

function getStoreName(storeId: string) {
  const store = storeOptions.value.find((s) => String(s.id) === storeId);
  return store ? store.storeName : '-';
}

function getStatusLabel(status?: string | null) {
  const map: Record<string, string> = {
    UPLOADED: '已上传',
    PARSING: '解析中',
    PARSED: '已解析',
    FAILED: '解析失败',
    PENDING: '待索引',
    INDEXING: '索引中',
    INDEXED: '已索引',
  };
  return status ? (map[status] ?? status) : '-';
}

function getParseStatusType(status?: string | null) {
  const success = ['PARSED'];
  const warning = ['UPLOADED', 'PARSING'];
  const danger = ['FAILED'];
  if (!status) return 'info';
  if (success.includes(status)) return 'success';
  if (warning.includes(status)) return 'warning';
  if (danger.includes(status)) return 'danger';
  return 'info';
}

function getIndexStatusType(status?: string | null) {
  const success = ['INDEXED'];
  const warning = ['PENDING', 'INDEXING'];
  const danger = ['FAILED'];
  if (!status) return 'info';
  if (success.includes(status)) return 'success';
  if (warning.includes(status)) return 'warning';
  if (danger.includes(status)) return 'danger';
  return 'info';
}

onMounted(() => {
  const routeStoreId = route.query.storeId;
  if (typeof routeStoreId === 'string') {
    queryForm.storeId = routeStoreId;
  }
  loadStores();
  loadDocs();
});
</script>

<template>
  <section class="page-panel rag-doc-page">
    <div class="page-panel__header">
      <h2>知识文档</h2>
      <span>上传自动解析，切片手动触发</span>
    </div>

    <RagFlowOverview :documents="docRows" />
    <div class="task-board-wrap">
      <RagChunkTaskBoard :total="docRows.length" :parsed="parsedCount" :failed="failedCount" />
    </div>

    <div class="document-query-bar" data-test="document-query-bar">
      <el-form class="document-query-form" data-test="document-query-form" inline>
        <el-form-item label="知识库">
          <el-select
            v-model="queryForm.storeId"
            data-test="doc-store-filter"
            placeholder="请选择"
            clearable
            class="query-control query-control--select"
          >
            <el-option
              v-for="store in storeOptions"
              :key="String(store.id)"
              :label="store.storeName"
              :value="String(store.id)"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="解析状态">
          <el-select
            v-model="queryForm.parseStatus"
            data-test="doc-parse-filter"
            placeholder="请选择"
            clearable
            class="query-control query-control--select"
          >
            <el-option label="已上传" value="UPLOADED" />
            <el-option label="解析中" value="PARSING" />
            <el-option label="已解析" value="PARSED" />
            <el-option label="解析失败" value="FAILED" />
          </el-select>
        </el-form-item>
        <el-form-item label="索引状态">
          <el-select
            v-model="queryForm.indexStatus"
            data-test="doc-index-filter"
            placeholder="请选择"
            clearable
            class="query-control query-control--select"
          >
            <el-option label="待索引" value="PENDING" />
            <el-option label="索引中" value="INDEXING" />
            <el-option label="已索引" value="INDEXED" />
            <el-option label="索引失败" value="FAILED" />
          </el-select>
        </el-form-item>
        <el-form-item label="启用状态">
          <el-select
            v-model="queryForm.enabled"
            data-test="doc-enabled-filter"
            placeholder="请选择"
            clearable
            class="query-control query-control--select"
          >
            <el-option label="启用" value="true" />
            <el-option label="停用" value="false" />
          </el-select>
        </el-form-item>
        <el-form-item label="关键词">
          <el-input
            v-model="queryForm.keyword"
            data-test="doc-keyword-input"
            placeholder="搜索标题/摘要/备注"
            clearable
            class="query-control query-control--keyword"
            @keyup.enter="handleSearch"
          />
        </el-form-item>
        <el-form-item class="document-query-form__actions">
          <el-button data-test="doc-search" type="primary" :icon="Search" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
          <el-button
            data-test="open-batch-chunk"
            :icon="Operation"
            :disabled="selectedParsedCount === 0"
            @click="openBatchChunkDialog"
          >
            批量切片（{{ selectedParsedCount }}）
          </el-button>
          <el-button
            data-test="retry-batch-parse"
            :loading="retryParsing"
            :disabled="selectedFailedCount === 0"
            @click="retryParseRows(selectedDocuments)"
          >
            重试解析（{{ selectedFailedCount }}）
          </el-button>
          <el-button
            data-test="open-doc-upload"
            type="primary"
            :icon="UploadFilled"
            @click="openUploadDialog"
          >
            批量上传
          </el-button>
        </el-form-item>
      </el-form>
    </div>

    <el-table
      v-loading="loading"
      :data="filteredRows"
      border
      stripe
      style="width: 100%"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="48" align="center" />
      <el-table-column type="index" label="编号" width="70" align="center" />
      <el-table-column prop="documentTitle" label="文档标题" min-width="180" show-overflow-tooltip />
      <el-table-column label="所属知识库" width="150">
        <template #default="{ row }">
          {{ getStoreName(row.storeId) }}
        </template>
      </el-table-column>
      <el-table-column label="解析状态" width="110">
        <template #default="{ row }">
          <el-tag :type="getParseStatusType(row.parseStatus)" size="small">
            {{ getStatusLabel(row.parseStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="索引状态" width="110">
        <template #default="{ row }">
          <el-tag :type="getIndexStatusType(row.indexStatus)" size="small">
            {{ getStatusLabel(row.indexStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="启用" width="80" align="center">
        <template #default="{ row }">
          <el-switch
            :model-value="row.enabled ?? false"
            size="small"
            @change="toggleEnabled(row)"
          />
        </template>
      </el-table-column>
      <el-table-column prop="documentSummary" label="摘要" min-width="160" show-overflow-tooltip />
      <el-table-column prop="createTime" label="创建时间" width="170" />
      <el-table-column label="操作" width="280" fixed="right">
        <template #default="{ row }">
          <el-button
            :data-test="`doc-chunk-${row.id}`"
            link
            type="primary"
            :disabled="row.parseStatus !== 'PARSED'"
            @click="openChunkDialog([row])"
          >
            切片
          </el-button>
          <el-button
            :data-test="`doc-retry-parse-${row.id}`"
            link
            type="warning"
            :disabled="row.parseStatus !== 'FAILED'"
            @click="retryParseRows([row])"
          >
            重试解析
          </el-button>
          <el-button :data-test="`doc-edit-${row.id}`" link type="primary" @click="openEditDialog(row)">编辑</el-button>
          <el-button link type="danger" @click="removeDoc(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-empty v-if="!loading && filteredRows.length === 0" description="暂无知识文档" />

    <RagDocumentBatchUploadDialog
      v-model="uploadDialogVisible"
      :stores="storeOptions"
      :locked-store-id="queryForm.storeId || null"
      @uploaded="loadDocs"
    />

    <el-dialog
      v-model="chunkDialogVisible"
      data-test="document-chunk-dialog"
      title="切片配置"
      width="620px"
    >
      <el-form :model="chunkForm" label-width="112px">
        <el-form-item label="文档数量">
          <el-tag>{{ chunkForm.documentIds.length }} 个文档</el-tag>
        </el-form-item>
        <el-form-item label="切片方式">
          <el-radio-group v-model="chunkForm.chunkStrategy" class="chunk-strategy-group">
            <el-radio
              v-for="strategy in chunkStrategyOptions"
              :key="strategy.value"
              :value="strategy.value"
              class="chunk-strategy-option"
            >
              <span class="chunk-strategy-option__label">{{ strategy.label }}</span>
              <small>{{ strategy.description }}</small>
            </el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-if="chunkForm.chunkStrategy === RAG_CHUNK_STRATEGY.FIXED_LENGTH" label="切片长度">
          <el-input-number v-model="chunkForm.chunkSize" :min="100" :max="4000" :step="100" />
        </el-form-item>
        <el-form-item v-if="chunkForm.chunkStrategy === RAG_CHUNK_STRATEGY.FIXED_LENGTH" label="重叠长度">
          <el-input-number v-model="chunkForm.chunkOverlap" :min="0" :max="1000" :step="20" />
        </el-form-item>
        <el-form-item v-if="chunkForm.chunkStrategy === RAG_CHUNK_STRATEGY.DELIMITER" label="分隔符">
          <el-input v-model="chunkForm.delimiter" maxlength="20" placeholder="如 。、换行符或自定义符号" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="chunkDialogVisible = false">取消</el-button>
        <el-button
          data-test="document-chunk-submit"
          type="primary"
          :loading="parseSubmitting"
          @click="submitChunk"
        >
          开始切片
        </el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="editDialogVisible" title="编辑文档" width="560px">
      <el-form :model="editForm" label-width="96px">
        <el-form-item label="文档标题" required>
          <el-input v-model="editForm.documentTitle" />
        </el-form-item>
        <el-form-item label="文档摘要">
          <el-input v-model="editForm.documentSummary" type="textarea" :rows="3" />
        </el-form-item>
        <el-form-item label="启用">
          <el-switch v-model="editForm.enabled" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="editForm.remark" type="textarea" :rows="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="submitEdit">保存</el-button>
      </template>
    </el-dialog>
  </section>
</template>

<style scoped>
.rag-doc-page {
  display: flex;
  flex-direction: column;
}

.task-board-wrap {
  padding: 10px 28px 0;
}

.document-query-bar {
  padding: 18px 28px 17px;
  border-bottom: 1px solid #e8edf5;
  background: #ffffff;
}

.document-query-form {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.document-query-form :deep(.el-form-item) {
  margin: 0;
}

.document-query-form :deep(.el-form-item__label) {
  height: 38px;
  padding-right: 8px;
  color: #606266;
  font-weight: 500;
  line-height: 38px;
}

.document-query-form :deep(.el-input__wrapper),
.document-query-form :deep(.el-select__wrapper) {
  min-height: 38px;
  border-radius: 4px;
  box-shadow: 0 0 0 1px #d8dee9 inset;
}

.document-query-form :deep(.el-input__wrapper:hover),
.document-query-form :deep(.el-select__wrapper:hover) {
  box-shadow: 0 0 0 1px #b9c6d8 inset;
}

.query-control--select {
  width: 168px;
}

.query-control--keyword {
  width: 225px;
}

.document-query-form__actions {
  margin-left: auto;
}

.document-query-form__actions :deep(.el-form-item__content) {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.chunk-strategy-group {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  width: 100%;
}

.chunk-strategy-option {
  align-items: flex-start;
  height: auto;
  margin-right: 0;
  padding: 10px 12px;
  border: 1px solid #d8dee9;
  border-radius: 4px;
}

.chunk-strategy-option :deep(.el-radio__label) {
  display: flex;
  flex-direction: column;
  gap: 4px;
  line-height: 1.4;
}

.chunk-strategy-option__label {
  color: #303133;
  font-weight: 600;
}

.chunk-strategy-option small {
  color: #7a8599;
  font-size: 12px;
}

@media (max-width: 768px) {
  .task-board-wrap {
    padding: 10px 16px 0;
  }

  .document-query-bar {
    padding: 16px;
  }

  .document-query-form {
    flex-direction: column;
    align-items: stretch;
  }

  .query-control--select,
  .query-control--keyword {
    width: 100%;
  }

  .document-query-form__actions {
    margin-left: 0;
  }

  .document-query-form__actions :deep(.el-form-item__content) {
    justify-content: flex-end;
  }

  .chunk-strategy-group {
    grid-template-columns: 1fr;
  }
}
</style>
