<template>
  <div class="document-list">
    <div class="list-header">
      <el-button type="primary" @click="handleUploadClick">
        <el-icon><Upload /></el-icon>
        上传文档
      </el-button>
      <el-button type="success" @click="handleBatchUploadClick">
        <el-icon><Upload /></el-icon>
        批量上传
      </el-button>
      <el-button type="warning" @click="handleJsonUploadClick">
        <el-icon><Upload /></el-icon>
        JSON上传
      </el-button>
      <input
        ref="fileInputRef"
        type="file"
        accept=".txt,.md,.pdf,.doc,.docx,.xls,.xlsx"
        style="display: none"
        @change="handleFileSelect"
      />
      <input
        ref="batchFileInputRef"
        type="file"
        accept=".zip"
        style="display: none"
        @change="handleBatchFileSelect"
      />
      <input
        ref="jsonFileInputRef"
        type="file"
        accept=".json,.jsonl,.txt"
        style="display: none"
        @change="handleJsonFileSelect"
      />
    </div>

    <el-table :data="documents" v-loading="loading" stripe>
      <el-table-column prop="fileName" label="文件名" min-width="200" />
      <el-table-column prop="status" label="状态" width="120">
        <template #default="{ row }">
          <el-tag :type="getStatusType(row.status)" size="small">
            {{ getStatusLabel(row.status) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="元数据" min-width="200">
        <template #default="{ row }">
          <div class="metadata-preview" v-if="row.metadata && Object.keys(row.metadata).length > 0">
            <el-tag
              v-for="(value, key) in getPreviewMetadata(row.metadata)"
              :key="key"
              size="small"
              type="info"
              class="metadata-tag"
            >
              {{ key }}: {{ formatMetadataValue(value) }}
            </el-tag>
            <el-tag v-if="Object.keys(row.metadata).length > 3" size="small" type="info">
              +{{ Object.keys(row.metadata).length - 3 }}
            </el-tag>
          </div>
          <span v-else class="no-metadata">-</span>
        </template>
      </el-table-column>
      <el-table-column prop="createdAt" label="上传时间" width="180">
        <template #default="{ row }">
          {{ formatDate(row.createdAt) }}
        </template>
      </el-table-column>
      <el-table-column label="操作" width="180">
        <template #default="{ row }">
          <el-button type="primary" link size="small" @click="handleEditMetadata(row)">
            <el-icon><Edit /></el-icon>
            编辑元数据
          </el-button>
          <el-button type="danger" link size="small" @click="handleDelete(row)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <div class="pagination-wrapper" v-if="pagination.total > 0">
      <el-pagination
        v-model:current-page="currentPage"
        :page-size="pagination.pageSize"
        :total="pagination.total"
        layout="total, prev, pager, next"
        @current-change="loadDocuments"
      />
    </div>

    <el-dialog
      v-model="uploadDialogVisible"
      title="上传文档"
      width="700px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form :model="uploadForm" :rules="uploadRules" ref="uploadFormRef" label-width="80px">
        <el-form-item label="文件">
          <div class="file-info" v-if="selectedFile">
            <el-icon><Document /></el-icon>
            <span>{{ selectedFile.name }}</span>
            <el-tag size="small" type="info">{{ formatFileSize(selectedFile.size) }}</el-tag>
          </div>
          <el-button v-else @click="handleUploadClick">选择文件</el-button>
        </el-form-item>

        <el-divider content-position="left">元数据配置 [AC-IDSMETA-15]</el-divider>

        <MetadataForm
          ref="metadataFormRef"
          scope="kb_document"
          v-model="uploadForm.metadata"
          :is-new-object="true"
          :col-span="12"
        />
      </el-form>
      <template #footer>
        <el-button @click="uploadDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="uploading" @click="handleUpload">
          上传
        </el-button>
      </template>
    </el-dialog>

    <el-dialog
      v-model="editDialogVisible"
      title="编辑元数据"
      width="600px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <MetadataForm
        ref="editMetadataFormRef"
        scope="kb_document"
        v-model="editForm.metadata"
        :is-new-object="false"
        :show-deprecated="true"
        :col-span="12"
      />
      <template #footer>
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="handleSaveMetadata">
          保存
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Upload, Edit, Document } from '@element-plus/icons-vue'
import { listDocuments, deleteDocument, getIndexJob } from '@/api/knowledge-base'
import { metadataSchemaApi } from '@/api/metadata-schema'
import { MetadataForm } from '@/components/metadata'
import type { Document as DocType, IndexJob } from '@/types/knowledge-base'
import type { MetadataPayload } from '@/types/metadata'
import { useTenantStore } from '@/stores/tenant'

interface DocumentWithMetadata extends DocType {
  metadata?: MetadataPayload
}

const props = defineProps<{
  kbId: string
}>()

const emit = defineEmits<{
  (e: 'upload-success'): void
}>()

const tenantStore = useTenantStore()
const loading = ref(false)
const documents = ref<DocumentWithMetadata[]>([])
const currentPage = ref(1)
const pagination = ref({
  page: 1,
  pageSize: 20,
  total: 0,
  totalPages: 0
})

const fileInputRef = ref<HTMLInputElement>()
const batchFileInputRef = ref<HTMLInputElement>()
const jsonFileInputRef = ref<HTMLInputElement>()
const uploadDialogVisible = ref(false)
const editDialogVisible = ref(false)
const uploading = ref(false)
const saving = ref(false)
const selectedFile = ref<File | null>(null)
const uploadFormRef = ref()
const metadataFormRef = ref()
const editMetadataFormRef = ref()
const currentEditDoc = ref<DocumentWithMetadata | null>(null)

const uploadForm = ref({
  metadata: {} as MetadataPayload
})

const editForm = ref({
  metadata: {} as MetadataPayload
})

const uploadRules = {
  file: [{ required: true, message: '请选择文件', trigger: 'change' }]
}

const getStatusType = (status: string): '' | 'success' | 'warning' | 'danger' | 'info' => {
  const typeMap: Record<string, '' | 'success' | 'warning' | 'danger' | 'info'> = {
    pending: 'info',
    processing: 'warning',
    completed: 'success',
    failed: 'danger'
  }
  return typeMap[status] || 'info'
}

const getStatusLabel = (status: string) => {
  const labelMap: Record<string, string> = {
    pending: '待处理',
    processing: '处理中',
    completed: '已完成',
    failed: '失败'
  }
  return labelMap[status] || status
}

const formatDate = (dateStr: string) => {
  if (!dateStr) return ''
  const date = new Date(dateStr)
  return date.toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit'
  })
}

const formatFileSize = (bytes: number) => {
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}

const getPreviewMetadata = (metadata: MetadataPayload) => {
  const keys = Object.keys(metadata).slice(0, 3)
  const result: MetadataPayload = {}
  keys.forEach(key => {
    result[key] = metadata[key]
  })
  return result
}

const formatMetadataValue = (value: string | number | boolean | string[] | undefined): string => {
  if (value === undefined || value === null) return ''
  if (Array.isArray(value)) return value.join(', ')
  return String(value)
}

const loadDocuments = async () => {
  loading.value = true
  try {
    const res = await listDocuments({
      kb_id: props.kbId,
      page: currentPage.value,
      page_size: pagination.value.pageSize
    })
    documents.value = res.data || []
    pagination.value = res.pagination
  } catch (error) {
    ElMessage.error('加载文档列表失败')
  } finally {
    loading.value = false
  }
}

const handleUploadClick = () => {
  fileInputRef.value?.click()
}

const handleBatchUploadClick = () => {
  batchFileInputRef.value?.click()
}

const handleJsonUploadClick = () => {
  jsonFileInputRef.value?.click()
}

const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return

  const allowedExtensions = ['.txt', '.md', '.pdf', '.doc', '.docx', '.xls', '.xlsx']
  const ext = '.' + file.name.split('.').pop()?.toLowerCase()

  if (!allowedExtensions.includes(ext)) {
    ElMessage.error('不支持的文件格式')
    return
  }

  const maxSize = 50 * 1024 * 1024
  if (file.size > maxSize) {
    ElMessage.error('文件大小不能超过 50MB')
    return
  }

  selectedFile.value = file
  uploadForm.value.metadata = {}
  uploadDialogVisible.value = true

  if (fileInputRef.value) {
    fileInputRef.value.value = ''
  }
}

const handleBatchFileSelect = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return

  if (!file.name.toLowerCase().endsWith('.zip')) {
    ElMessage.error('请上传 .zip 格式的压缩包')
    if (batchFileInputRef.value) {
      batchFileInputRef.value.value = ''
    }
    return
  }

  const maxSize = 100 * 1024 * 1024
  if (file.size > maxSize) {
    ElMessage.error('压缩包大小不能超过 100MB')
    if (batchFileInputRef.value) {
      batchFileInputRef.value.value = ''
    }
    return
  }

  try {
    loading.value = true
    const formData = new FormData()
    formData.append('file', file)
    formData.append('kb_id', props.kbId)

    const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
    const apiKey = import.meta.env.VITE_APP_API_KEY || ''
    const response = await fetch(`${baseUrl}/admin/kb/documents/batch-upload`, {
      method: 'POST',
      headers: {
        'X-Tenant-Id': tenantStore.currentTenantId,
        'X-API-Key': apiKey
      },
      body: formData
    })

    const result = await response.json()
    if (result.success) {
      const { total, succeeded, failed, results } = result
      ElMessage.success(`批量上传完成！成功: ${succeeded}, 失败: ${failed}, 总计: ${total}`)
      
      // 收集所有成功的任务ID，稍后串行轮询
      const jobIds: string[] = []
      for (const item of results) {
        if (item.status === 'created' && item.jobId) {
          jobIds.push(item.jobId)
        }
      }
      
      // 串行轮询所有任务，避免并发请求触发限流
      if (jobIds.length > 0) {
        pollJobStatusSequential(jobIds)
      }
      
      emit('upload-success')
      loadDocuments()
    } else {
      ElMessage.error(result.message || '批量上传失败')
    }
  } catch (error) {
    ElMessage.error('批量上传失败，请重试')
    console.error('Batch upload error:', error)
  } finally {
    loading.value = false
    if (batchFileInputRef.value) {
      batchFileInputRef.value.value = ''
    }
  }
}

const handleJsonFileSelect = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return

  const fileName = file.name.toLowerCase()
  if (!fileName.endsWith('.json') && !fileName.endsWith('.jsonl') && !fileName.endsWith('.txt')) {
    ElMessage.error('请上传 .json、.jsonl 或 .txt 格式的文件')
    if (jsonFileInputRef.value) {
      jsonFileInputRef.value.value = ''
    }
    return
  }

  try {
    loading.value = true
    ElMessage.info('正在上传 JSON 文件...')
    
    const formData = new FormData()
    formData.append('file', file)
    
    const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
    const apiKey = import.meta.env.VITE_APP_API_KEY || ''
    const response = await fetch(`${baseUrl}/admin/kb/${props.kbId}/documents/json-batch?tenant_id=${tenantStore.currentTenantId}`, {
      method: 'POST',
      headers: {
        'X-Tenant-Id': tenantStore.currentTenantId,
        'X-API-Key': apiKey
      },
      body: formData
    })

    const result = await response.json()
    if (result.success) {
      ElMessage.success(`JSON 批量上传成功！成功: ${result.succeeded}, 失败: ${result.failed}`)
      
      if (result.valid_metadata_fields) {
        console.log('有效的元数据字段:', result.valid_metadata_fields)
      }
      
      if (result.failed > 0) {
        const failedItems = result.results.filter((r: any) => !r.success)
        console.warn('失败的项目:', failedItems)
      }
      
      emit('upload-success')
      loadDocuments()
    } else {
      ElMessage.error(result.message || 'JSON 批量上传失败')
    }
  } catch (error) {
    ElMessage.error('JSON 批量上传失败，请重试')
    console.error('JSON batch upload error:', error)
  } finally {
    loading.value = false
    if (jsonFileInputRef.value) {
      jsonFileInputRef.value.value = ''
    }
  }
}

const handleUpload = async () => {
  if (!selectedFile.value) {
    ElMessage.warning('请选择文件')
    return
  }

  if (metadataFormRef.value) {
    const validation = await metadataFormRef.value.validate()
    if (!validation.valid) {
      ElMessage.warning('请完善必填的元数据字段')
      return
    }
  }

  uploading.value = true
  try {
    const formData = new FormData()
    formData.append('file', selectedFile.value)
    formData.append('kb_id', props.kbId)
    formData.append('metadata', JSON.stringify(uploadForm.value.metadata))

    const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
    const apiKey = import.meta.env.VITE_APP_API_KEY || ''
    const response = await fetch(`${baseUrl}/admin/kb/documents`, {
      method: 'POST',
      headers: {
        'X-Tenant-Id': tenantStore.currentTenantId,
        'X-API-Key': apiKey
      },
      body: formData
    })

    const result = await response.json()
    if (result.jobId) {
      ElMessage.success('文档上传成功，正在处理中...')
      emit('upload-success')
      loadDocuments()
      pollJobStatus(result.jobId)
    } else {
      ElMessage.error(result.message || '上传失败')
    }
  } catch (error) {
    ElMessage.error('上传失败，请重试')
  } finally {
    uploading.value = false
    uploadDialogVisible.value = false
    selectedFile.value = null
  }
}

const handleEditMetadata = (doc: DocumentWithMetadata) => {
  currentEditDoc.value = doc
  editForm.value.metadata = doc.metadata || {}
  editDialogVisible.value = true
}

const handleSaveMetadata = async () => {
  if (!currentEditDoc.value) return

  if (editMetadataFormRef.value) {
    const validation = await editMetadataFormRef.value.validate()
    if (!validation.valid) {
      ElMessage.warning('请完善必填的元数据字段')
      return
    }
  }

  saving.value = true
  try {
    const baseUrl = import.meta.env.VITE_APP_BASE_API || '/api'
    const apiKey = import.meta.env.VITE_APP_API_KEY || ''
    const response = await fetch(`${baseUrl}/admin/kb/documents/${currentEditDoc.value.docId}/metadata`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
        'X-Tenant-Id': tenantStore.currentTenantId,
        'X-API-Key': apiKey
      },
      body: JSON.stringify({ metadata: editForm.value.metadata })
    })

    if (response.ok) {
      ElMessage.success('元数据更新成功')
      loadDocuments()
      editDialogVisible.value = false
    } else {
      const result = await response.json()
      ElMessage.error(result.message || '更新失败')
    }
  } catch (error) {
    ElMessage.error('更新失败，请重试')
  } finally {
    saving.value = false
  }
}

const pollJobStatus = async (jobId: string) => {
  const maxPolls = 60
  let pollCount = 0

  const poll = async () => {
    if (pollCount >= maxPolls) return
    pollCount++

    try {
      const job: IndexJob = await getIndexJob(jobId)
      if (job.status === 'completed') {
        ElMessage.success('文档处理完成')
        loadDocuments()
      } else if (job.status === 'failed') {
        ElMessage.error(`文档处理失败: ${job.errorMsg || '未知错误'}`)
        loadDocuments()
      } else {
        setTimeout(poll, 10000)  // 10秒轮询一次，避免触发限流
      }
    } catch (error: any) {
      if (error.status === 429) {
        console.warn('请求过于频繁，稍后重试')
        setTimeout(poll, 15000)  // 被限流后等待15秒
      } else {
        console.error('轮询任务状态失败', error)
      }
    }
  }

  setTimeout(poll, 5000)  // 首次轮询等待5秒
}

// 串行轮询多个任务，避免并发触发限流
const pollJobStatusSequential = async (jobIds: string[]) => {
  const pendingJobs = new Set(jobIds)
  const maxPolls = 60
  let pollCount = 0

  const pollAll = async () => {
    if (pollCount >= maxPolls || pendingJobs.size === 0) return
    pollCount++

    const completedJobs: string[] = []
    
    for (const jobId of pendingJobs) {
      try {
        const job: IndexJob = await getIndexJob(jobId)
        if (job.status === 'completed') {
          completedJobs.push(jobId)
        } else if (job.status === 'failed') {
          completedJobs.push(jobId)
          console.error(`文档处理失败: ${job.errorMsg || '未知错误'}`)
        }
      } catch (error: any) {
        if (error.status === 429) {
          console.warn('请求过于频繁，稍后重试')
          break  // 被限流时停止本轮轮询，等待下次
        } else {
          console.error('轮询任务状态失败', error)
        }
      }
    }

    // 移除已完成的任务
    completedJobs.forEach(jobId => pendingJobs.delete(jobId))

    if (pendingJobs.size > 0) {
      setTimeout(pollAll, 10000)  // 10秒后再次轮询
    } else {
      ElMessage.success('所有文档处理完成')
      loadDocuments()
    }
  }

  setTimeout(pollAll, 5000)  // 首次轮询等待5秒
}

const handleDelete = async (row: DocumentWithMetadata) => {
  try {
    await ElMessageBox.confirm('确定要删除该文档吗？', '确认删除', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    await deleteDocument(row.docId)
    ElMessage.success('删除成功')
    loadDocuments()
    emit('upload-success')
  } catch (error) {
    if (error !== 'cancel') {
      ElMessage.error('删除失败')
    }
  }
}

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

<style scoped>
.document-list {
  padding: 0 16px;
}

.list-header {
  margin-bottom: 16px;
  display: flex;
  gap: 12px;
}

.pagination-wrapper {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
}

.metadata-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.metadata-tag {
  margin: 0;
}

.no-metadata {
  color: var(--el-text-color-placeholder);
}

.file-info {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: var(--el-fill-color-light);
  border-radius: 4px;
}
</style>
