<template>
  <div class="source-panel">
    <div class="panel-header">
      <h3>来源</h3>
      <a-badge :count="`${sourceCount}/${maxSources}`" :number-style="{ backgroundColor: sourceCount >= maxSources ? '#f5222d' : '#1890ff' }" />
    </div>

    <a-button
      type="dashed"
      block
      @click="showAddDialog = true"
      :disabled="sourceCount >= maxSources"
      style="margin-bottom: 12px"
    >
      <PlusOutlined /> 添加来源
    </a-button>

    <div class="source-list" v-if="sources.length">
      <SourceItem
        v-for="source in sources"
        :key="source.id"
        :source="source"
        @toggle="handleToggle"
        @delete="handleDelete"
        @retry="handleRetry"
        @preview="handlePreview"
      />
    </div>
    <a-empty v-else description="暂无来源" :image-style="{ height: '60px' }" />

    <AddSourceDialog
      :open="showAddDialog"
      :notebook-id="notebookId"
      @close="showAddDialog = false"
      @added="handleSourceAdded"
    />

    <!-- Document preview modal -->
    <DocumentQuickPreview
      v-if="previewDocId"
      :doc-id="previewDocId"
      :open="previewOpen"
      :matched-chunks="previewChunks"
      :fallback-text="previewFallback"
      @update:open="(val: boolean) => { if (!val) { previewDocId = ''; previewOpen = false } }"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { PlusOutlined } from '@ant-design/icons-vue'
import { message, Modal } from 'ant-design-vue'
import { useNotebookStore } from '@/stores/notebook'
import request from '@/api/request'
import SourceItem from './SourceItem.vue'
import AddSourceDialog from './AddSourceDialog.vue'
import DocumentQuickPreview from '@/components/DocumentQuickPreview.vue'

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

const store = useNotebookStore()
const sources = computed(() => store.sources)
const sourceCount = computed(() => store.sourceCount)
const maxSources = store.maxSources

const showAddDialog = ref(false)
const previewDocId = ref('')
const previewOpen = ref(false)
const previewChunks = ref<any[]>([])
const previewFallback = ref('')

// Polling for ingest status
let pollTimer: ReturnType<typeof setInterval> | null = null

function startPolling() {
  if (pollTimer) return
  pollTimer = setInterval(async () => {
    const hasPending = sources.value.some(
      (s) => s.ingest_status === 'pending' || s.ingest_status === 'processing',
    )
    if (hasPending) {
      await store.refreshSources(props.notebookId)
    } else if (pollTimer) {
      clearInterval(pollTimer)
      pollTimer = null
    }
  }, 3000)
}

function handleSourceAdded() {
  showAddDialog.value = false
  startPolling()
}

async function handleToggle(id: string, selected: boolean) {
  await store.toggleSource(props.notebookId, id, selected)
}

async function handleDelete(id: string) {
  Modal.confirm({
    title: '确认删除',
    content: '删除来源后，相关的知识内容也会被清理。确定删除？',
    okText: '删除',
    okType: 'danger',
    async onOk() {
      await store.removeSource(props.notebookId, id)
      message.success('已删除')
    },
  })
}

async function handleRetry(id: string) {
  await store.retrySource(props.notebookId, id)
  message.info('正在重新入库')
  startPolling()
}

async function handlePreview(docId: string) {
  previewDocId.value = docId
  previewChunks.value = []
  previewFallback.value = ''

  // Find which source this doc belongs to
  const source = sources.value.find(s => s.doc_id === docId)
  if (source) {
    try {
      const { data } = await request.get(
        `/api/v1/notebook/${props.notebookId}/sources/${source.id}/chunks`,
      )
      if (data?.chunks?.length) {
        previewChunks.value = data.chunks.map((c: any) => ({
          text: c.content || '',
          page_number: c.page_number,
          page_numbers: c.page_numbers || [],
          heading_hierarchy: c.heading_hierarchy || [],
          element_type: c.element_type || 'paragraph',
          chunk_index: c.chunk_index,
        }))
      }
    } catch {
      if (source.summary) {
        previewFallback.value = source.summary
      }
    }
  }

  previewOpen.value = true
}

// Start polling if there are pending sources on mount
onMounted(() => {
  const hasPending = sources.value.some(
    (s) => s.ingest_status === 'pending' || s.ingest_status === 'processing',
  )
  if (hasPending) startPolling()
})

onUnmounted(() => {
  if (pollTimer) {
    clearInterval(pollTimer)
    pollTimer = null
  }
})

watch(
  () => sources.value.some((s) => s.ingest_status === 'pending' || s.ingest_status === 'processing'),
  (hasPending) => {
    if (hasPending) startPolling()
  },
)
</script>

<style scoped lang="less">
.source-panel {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 16px;
  overflow: hidden;
}

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

  h3 {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
  }
}

.source-list {
  flex: 1;
  overflow-y: auto;
}
</style>
