<template>
  <div class="document-upload">
    <div class="document-upload__toolbar">
      <a-upload-dragger
        class="document-upload__dragger"
        :multiple="true"
        :custom-request="handleUpload"
        :before-upload="beforeUpload"
        :show-upload-list="false"
        accept=".pdf,.docx,.doc,.md,.txt,.html,.csv,.json"
      >
        <p class="ant-upload-drag-icon">
          <InboxOutlined />
        </p>
        <p class="ant-upload-text">点击或拖拽文件到此区域上传</p>
        <p class="ant-upload-hint">
          支持 PDF、Word、Markdown、HTML、纯文本等格式
        </p>
      </a-upload-dragger>

      <a-button class="document-upload__preview-btn" @click="showPreview = true">
        <template #icon><EyeOutlined /></template>
        预览分段
      </a-button>
    </div>

    <a-spin v-if="kbStore.isUploading" tip="正在上传处理..." class="upload-spin" />

    <div v-if="kbStore.documents.length > 0" class="document-list">
      <a-divider>文档列表 ({{ kbStore.documents.length }})</a-divider>
      <a-table
        :data-source="kbStore.documents"
        :columns="docColumns"
        :loading="kbStore.isLoading"
        row-key="document_id"
        size="small"
        :pagination="{ pageSize: 10 }"
      >
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'status'">
            <a-tooltip
              :title="record.error_message"
              :open="record.status === 'failed' && record.error_message ? undefined : false"
            >
              <a-badge
                :status="statusBadge(record.status)"
                :text="statusLabel(record.status)"
              />
            </a-tooltip>
          </template>
          <template v-if="column.key === 'created_at'">
            {{ formatTime(record.created_at) }}
          </template>
          <template v-if="column.key === 'actions'">
            <a-space :size="4">
              <a-button
                v-if="record.status === 'failed'"
                type="link"
                size="small"
                :loading="retryingId === record.document_id"
                @click="handleRetry(record.document_id)"
              >
                重试
              </a-button>
              <a-popconfirm
                title="确定删除此文档？"
                @confirm="handleDelete(record.document_id)"
              >
                <a-button type="link" size="small" danger>删除</a-button>
              </a-popconfirm>
            </a-space>
          </template>
        </template>
      </a-table>
    </div>

    <a-empty
      v-else-if="!kbStore.isUploading && !kbStore.isLoading"
      description="暂无文档"
    />

    <SegmentPreview v-model:open="showPreview" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import { message } from 'ant-design-vue'
import { InboxOutlined, EyeOutlined } from '@ant-design/icons-vue'
import { useKnowledgeStore } from '@/stores/knowledge'
import SegmentPreview from './SegmentPreview.vue'

const kbStore = useKnowledgeStore()

const showPreview = ref(false)
const retryingId = ref<string | null>(null)

const docColumns = [
  { title: '文件名', dataIndex: 'filename', key: 'filename', ellipsis: true },
  { title: '状态', dataIndex: 'status', key: 'status', width: 140 },
  { title: '分块数', dataIndex: 'chunks', key: 'chunks', width: 80 },
  { title: '上传时间', dataIndex: 'created_at', key: 'created_at', width: 160 },
  { title: '操作', key: 'actions', width: 120 },
]

/** Status → badge status mapping (processing=blue, indexed=green, failed=red). */
function statusBadge(status: string): 'processing' | 'success' | 'error' | 'default' {
  switch (status) {
    case 'indexed':
      return 'success'
    case 'failed':
      return 'error'
    case 'pending':
    case 'parsing':
    case 'segmenting':
    case 'vectorizing':
      return 'processing'
    default:
      return 'default'
  }
}

function statusLabel(status: string): string {
  switch (status) {
    case 'pending':
      return '待处理'
    case 'parsing':
      return '解析中'
    case 'segmenting':
      return '分段中'
    case 'vectorizing':
      return '向量化中'
    case 'indexed':
      return '已索引'
    case 'failed':
      return '失败'
    default:
      return status
  }
}

function formatTime(isoStr: string): string {
  try {
    const d = new Date(isoStr)
    return d.toLocaleString('zh-CN')
  } catch {
    return isoStr
  }
}

function beforeUpload(file: File): boolean {
  const validExtensions = ['.pdf', '.docx', '.doc', '.md', '.txt', '.html', '.csv', '.json']
  const ext = '.' + file.name.split('.').pop()?.toLowerCase()
  if (!validExtensions.includes(ext)) {
    message.error(`不支持的文件格式: ${ext}`)
    return false
  }
  return true
}

async function handleUpload(options: { file: File; onSuccess?: () => void; onError?: (err: unknown) => void }): Promise<void> {
  try {
    await kbStore.uploadDocument(options.file)
    message.success(`${options.file.name} 上传成功`)
    options.onSuccess?.()
    await kbStore.fetchDocuments()
  } catch (err) {
    message.error(`${options.file.name} 上传失败`)
    options.onError?.(err)
  }
}

async function handleDelete(documentId: string): Promise<void> {
  try {
    await kbStore.deleteDocument(documentId)
    message.success('文档已删除')
  } catch {
    message.error('删除文档失败')
  }
}

async function handleRetry(documentId: string): Promise<void> {
  retryingId.value = documentId
  try {
    await kbStore.retryDocument(documentId)
    message.success('已触发重试')
  } catch (err) {
    const detail = err instanceof Error ? err.message : '重试失败'
    message.error(detail)
  } finally {
    retryingId.value = null
  }
}

/**
 * Poll document statuses while any document is in a non-terminal state.
 *
 * ponytail: the backend has no WS push for document status today, so we
 * poll the list endpoint every 5s while processing docs exist. Ceiling:
 * O(n) list refetch per tick; fine for hundreds of docs. Upgrade path:
 * subscribe to a dedicated document-status WS channel once the backend
 * emits one (see AGENTS.md ws protocol).
 */
const POLL_INTERVAL_MS = 5000
let pollTimer: ReturnType<typeof setInterval> | null = null

function startPolling(): void {
  stopPolling()
  pollTimer = setInterval(() => {
    if (kbStore.processingDocuments.length > 0) {
      kbStore.fetchDocuments()
    } else {
      stopPolling()
    }
  }, POLL_INTERVAL_MS)
}

function stopPolling(): void {
  if (pollTimer !== null) {
    clearInterval(pollTimer)
    pollTimer = null
  }
}

// Start/stop polling based on whether any docs are processing.
watch(
  () => kbStore.processingDocuments.length,
  (count) => {
    if (count > 0 && pollTimer === null) {
      startPolling()
    } else if (count === 0) {
      stopPolling()
    }
  },
)

onMounted(() => {
  kbStore.fetchDocuments()
  if (kbStore.processingDocuments.length > 0) {
    startPolling()
  }
})

onUnmounted(() => {
  stopPolling()
})
</script>

<style scoped>
.document-upload {
  padding: 8px 0;
}

.document-upload__toolbar {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.document-upload__dragger {
  flex: 1;
}

.document-upload__preview-btn {
  flex-shrink: 0;
  margin-top: 4px;
}

.upload-spin {
  display: block;
  text-align: center;
  padding: 16px;
}

.document-list {
  margin-top: 16px;
}
</style>
