<template>
  <div class="search-view">
    <div class="search-header">
      <SearchBar
        v-model="searchStore.query"
        placeholder="输入关键词或描述，如：关于机构改革的最新通知"
        :loading="searchStore.loading"
        @search="handleSearch"
      />
      <AdvancedFilter
        :filters="searchStore.filters"
        :org-options="orgFilterOptions"
        :category-options="categoryFilterOptions"
        :doc-type-options="docTypeFilterOptions"
        :scene-type-options="sceneTypeFilterOptions"
        :subject-word-options="mergedSubjectWordFilterOptions"
        @change="handleFilterChange"
        @reset="handleResetFilters"
      />
    </div>

    <a-row :gutter="24" v-if="searchStore.total > 0 || searchStore.loading">
      <a-col :span="17">
        <div class="result-header">
          <span>共找到 <strong>{{ searchStore.total }}</strong> 个相关文档</span>
          <span v-if="searchStore.total > 0" class="result-header__time">
            用时 {{ searchDuration }}ms
          </span>
        </div>

        <!-- batch selection removed -->

        <a-spin :spinning="searchStore.loading">
          <div class="result-list">
            <ResultCard
              v-for="doc in searchStore.results"
              :key="doc.doc_id"
              :doc="doc"
              :in-basket="isInBasket(doc.doc_id)"
              @click="goToDocument"
              @add-to-basket="addDocumentToBasket"
              @quick-preview="openQuickPreview"
              @view-relations="viewRelations"
            />
          </div>
        </a-spin>

        <div class="result-pagination">
          <a-pagination
            v-model:current="searchStore.page"
            :total="searchStore.total"
            :page-size="searchStore.pageSize"
            show-quick-jumper
            show-size-changer
            @change="handlePageChange"
          />
        </div>

        <!-- 权限说明 -->
        <div class="permission-notice">
          <LockOutlined />
          <span>权限说明：系统已根据您的权限自动过滤不可访问内容，当前显示均为可见范围内的结果。</span>
        </div>
      </a-col>

      <a-col :span="7">
        <div class="sidebar-sticky">
          <a-button block @click="basketStore.openDrawer" style="margin-bottom: 12px">
            参考资料篮（{{ basketStore.count }}项）
          </a-button>
        </div>

        <a-card title="结果分布" size="small" class="agg-card">
          <template v-if="searchStore.aggregations.by_org?.length">
            <h4>发文机关</h4>
            <div
              v-for="item in searchStore.aggregations.by_org?.slice(0, 8)"
              :key="item.key"
              class="agg-item"
              :class="{ 'agg-item--active': isFilterActive('issuing_org', item.key) }"
              @click="filterByOrg(item.key)"
            >
              <span class="agg-label">{{ item.key }}</span>
              <span class="agg-count">{{ item.count }}</span>
            </div>
          </template>

          <template v-if="searchStore.aggregations.by_type?.length">
            <a-divider style="margin: 8px 0" />
            <h4>文种分布</h4>
            <div
              v-for="item in searchStore.aggregations.by_type?.slice(0, 8)"
              :key="item.key"
              class="agg-item"
              :class="{ 'agg-item--active': isFilterActive('doc_type', item.key) }"
              @click="filterByType(item.key)"
            >
              <span class="agg-label">{{ item.key }}</span>
              <span class="agg-count">{{ item.count }}</span>
            </div>
          </template>

          <template v-if="searchStore.aggregations.by_category?.length">
            <a-divider style="margin: 8px 0" />
            <h4>知识分类</h4>
            <div
              v-for="item in searchStore.aggregations.by_category?.slice(0, 8)"
              :key="item.key"
              class="agg-item"
              :class="{ 'agg-item--active': isFilterActive('knowledge_category', item.key) }"
              @click="filterByCategory(item.key)"
            >
              <span class="agg-label">{{ item.key }}</span>
              <span class="agg-count">{{ item.count }}</span>
            </div>
          </template>

          <template v-if="searchStore.aggregations.by_year?.length">
            <a-divider style="margin: 8px 0" />
            <h4>年份分布</h4>
            <div
              v-for="item in searchStore.aggregations.by_year?.slice(0, 6)"
              :key="item.key"
              class="agg-item"
              :class="{ 'agg-item--active': searchStore.filters.publish_year === Number(item.key) }"
              @click="filterByYear(item.key)"
            >
              <span class="agg-label">{{ item.key }}</span>
              <span class="agg-count">{{ item.count }}</span>
            </div>
          </template>

          <template v-if="searchStore.aggregations.by_subject_words?.length">
            <a-divider style="margin: 8px 0" />
            <h4>主题词分布</h4>
            <div
              v-for="item in searchStore.aggregations.by_subject_words?.slice(0, 10)"
              :key="item.key"
              class="agg-item"
              :class="{ 'agg-item--active': isFilterActive('subject_words', item.key) }"
              @click="filterBySubjectWord(item.key)"
            >
              <span class="agg-label">{{ item.key }}</span>
              <span class="agg-count">{{ item.count }}</span>
            </div>
          </template>

          <div v-if="!hasAnyAggregation" class="agg-empty">
            搜索后显示分布统计
          </div>
        </a-card>
      </a-col>
    </a-row>

    <div v-else-if="!searchStore.loading && searchStore.query" class="empty-state">
      <a-empty description="未找到匹配的文档，请尝试调整关键词或筛选条件">
        <template #extra>
          <a-button type="primary" @click="router.push('/research')">前往研究分析</a-button>
        </template>
      </a-empty>
    </div>

    <div v-else-if="!searchStore.query" class="initial-state">
      <a-empty description="输入关键词开始搜索文件" />
    </div>

    <DocumentQuickPreview
      v-model:open="previewOpen"
      :doc-id="previewDocId"
      :highlights="previewHighlights"
      :matched-chunks="previewMatchedChunks"
      @open-detail="goToDocument"
      @import="openImportDialogById"
    />

    <ImportToResearchDialog
      v-model:open="importDialogOpen"
      :items="pendingImportItems"
      :title="importDialogTitle"
      @confirm="handleImportConfirm"
    />
  </div>
</template>

/**
 * 文档检索视图
 * 提供关键词搜索、高级筛选、聚合统计面板、批量选择与导入 Research 等功能。
 * 左侧为搜索结果列表（支持快速预览），右侧为资料篮和筛选统计卡片。
 */
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { LockOutlined } from '@ant-design/icons-vue'
import { useRouter } from 'vue-router'
import { fetchFilterOptions } from '@/api/search'
import { useResearchImport } from '@/composables/useResearchImport'
import { useSearchStore } from '@/stores/search'
import { useBasketStore } from '@/stores/basket'
import ImportToResearchDialog from '@/components/ImportToResearchDialog.vue'
import SearchBar from '@/components/SearchBar.vue'
import DocumentQuickPreview from '@/components/DocumentQuickPreview.vue'
import ResultCard from '@/components/ResultCard.vue'
import AdvancedFilter from '@/components/AdvancedFilter.vue'
import type { BasketItem } from '@/types/basket'
import type { ResearchImportDialogPayload } from '@/types/research-import'
import type { DocumentResult } from '@/types/search'

const router = useRouter()
const searchStore = useSearchStore()
const basketStore = useBasketStore()
const { applyImport } = useResearchImport()
const selectedDocIds = ref<string[]>([])
const searchDuration = ref(0)
const previewOpen = ref(false)
const previewDocId = ref<string>()
const previewHighlights = ref<string[]>([])
const previewMatchedChunks = ref<import('@/types/search').MatchedChunk[]>([])
const importDialogOpen = ref(false)
const importDialogTitle = ref('')
const pendingImportItems = ref<BasketItem[]>([])

// 根据 selectedDocIds 从结果中提取已选文档对象列表
const selectedDocs = computed(() => {
  const selectedSet = new Set(selectedDocIds.value)
  return searchStore.results.filter((doc) => selectedSet.has(doc.doc_id))
})

const categoryFilterOptions = ref<{ label: string; value: string }[]>([])
const docTypeFilterOptions = ref<{ label: string; value: string }[]>([])
const sceneTypeFilterOptions = ref<{ label: string; value: string }[]>([])
const subjectWordFilterOptions = ref<{ label: string; value: string }[]>([])

const mergedSubjectWordFilterOptions = computed(() => {
  const merged = new Map<string, { label: string; value: string }>()

  for (const item of subjectWordFilterOptions.value) {
    if (!item?.value) continue
    merged.set(item.value, item)
  }

  for (const item of searchStore.aggregations.by_subject_words || []) {
    if (!item?.key || merged.has(item.key)) continue
    merged.set(item.key, { label: item.key, value: item.key })
  }

  return Array.from(merged.values()).slice(0, 20)
})

const orgFilterOptions = computed(() => {
  return (searchStore.aggregations.by_org || []).map((item) => ({
    label: `${item.key} (${item.count})`,
    value: item.key,
  }))
})

onMounted(async () => {
  try {
    const opts = await fetchFilterOptions()
    categoryFilterOptions.value = opts.knowledge_categories || []
    docTypeFilterOptions.value = opts.doc_types || []
    sceneTypeFilterOptions.value = opts.document_scene_types || []
    subjectWordFilterOptions.value = opts.subject_words || []
  } catch (e) {
    console.warn('Failed to load filter options', e)
  }
})

// 搜索结果更新后，清理已不在当前结果页中的选中项
watch(
  () => searchStore.results,
  (results) => {
    const visibleIds = new Set(results.map((doc) => doc.doc_id))
    selectedDocIds.value = selectedDocIds.value.filter((docId) => visibleIds.has(docId))
  },
)

async function handleSearch(value: string) {
  searchStore.query = value
  const start = performance.now()
  await searchStore.search(true)
  searchDuration.value = Math.round(performance.now() - start)
}

async function handleFilterChange() {
  const start = performance.now()
  await searchStore.search(true)
  searchDuration.value = Math.round(performance.now() - start)
}

async function handleResetFilters() {
  searchStore.resetFilters()
  const start = performance.now()
  await searchStore.search(true)
  searchDuration.value = Math.round(performance.now() - start)
}

async function handlePageChange(page: number) {
  const start = performance.now()
  await searchStore.changePage(page)
  searchDuration.value = Math.round(performance.now() - start)
}

function goToDocument(docId: string) {
  router.push(`/doc/${docId}`)
}

function toggleSelect(docId: string) {
  if (selectedDocIds.value.includes(docId)) {
    selectedDocIds.value = selectedDocIds.value.filter((id) => id !== docId)
  } else {
    selectedDocIds.value = [...selectedDocIds.value, docId]
  }
}

function clearSelection() {
  selectedDocIds.value = []
}

function isInBasket(docId: string): boolean {
  return basketStore.items.some((item) => item.doc_id === docId)
}

function addDocumentToBasket(doc: DocumentResult) {
  const added = basketStore.addItem(toBasketItem(doc))
  if (added) {
    message.success(`已加入资料篮`)
  } else {
    message.warning('该资料已在资料篮中')
  }
}

function addSelectedToBasket() {
  let addedCount = 0
  for (const doc of selectedDocs.value) {
    if (basketStore.addItem(toBasketItem(doc))) addedCount++
  }
  if (addedCount > 0) {
    message.success(`已加入资料篮 ${addedCount} 项`)
  } else {
    message.warning('所选资料已在资料篮中')
  }
  selectedDocs.value = []
}

function openQuickPreview(doc: DocumentResult) {
  previewDocId.value = doc.doc_id
  previewHighlights.value = doc.highlights || []
  previewMatchedChunks.value = doc.matched_chunks || []
  previewOpen.value = true
}

function openImportDialogById(docId: string) {
  const doc = searchStore.results.find((item) => item.doc_id === docId)
  if (doc) {
    addDocumentToBasket(doc)
  }
}

function viewRelations(doc: DocumentResult) {
  router.push({
    path: `/doc/${doc.doc_id}`,
    query: { tab: 'graph' },
  })
}

function handleImportConfirm(payload: ResearchImportDialogPayload) {
  if (!pendingImportItems.value.length) return
  applyImport(pendingImportItems.value, payload)
}

function stripHtml(value: string) {
  return value.replace(/<[^>]+>/g, '')
}

/** 将搜索结果转换为资料篮条目格式 */
function toBasketItem(doc: DocumentResult): BasketItem {
  return {
    item_type: 'document',
    title: stripHtml(doc.title),
    selected_from: 'search',
    importance: 'reference',
    doc_id: doc.doc_id,
    content_hash: doc.content_hash,
    doc_code: doc.doc_number,
    added_at: Date.now(),
  }
}

const hasAnyAggregation = computed(() => {
  const agg = searchStore.aggregations
  return (agg.by_org?.length || agg.by_type?.length || agg.by_category?.length || agg.by_year?.length || agg.by_subject_words?.length)
})

/** Check if a filter value is currently active (for highlighting agg items) */
function isFilterActive(filterKey: string, value: string): boolean {
  const f = searchStore.filters as Record<string, unknown>
  const current = f[filterKey]
  if (Array.isArray(current)) return current.includes(value)
  return current === value
}

function filterByOrg(org: string) {
  // Toggle: click again to remove
  const current = searchStore.filters.issuing_org
  if (Array.isArray(current) && current.includes(org)) {
    searchStore.filters.issuing_org = undefined
  } else {
    searchStore.filters.issuing_org = [org]
  }
  searchStore.search(true)
}

function filterByType(type: string) {
  const current = searchStore.filters.doc_type
  if (Array.isArray(current) && current.includes(type)) {
    searchStore.filters.doc_type = undefined
  } else {
    searchStore.filters.doc_type = [type]
  }
  searchStore.search(true)
}

function filterByCategory(category: string) {
  const current = searchStore.filters.knowledge_category
  if (Array.isArray(current) && current.includes(category)) {
    searchStore.filters.knowledge_category = undefined
  } else {
    searchStore.filters.knowledge_category = [category]
  }
  searchStore.search(true)
}

function filterByYear(year: string) {
  const parsedYear = Number.parseInt(year, 10)
  if (Number.isNaN(parsedYear)) return
  // Toggle: click again to remove
  if (searchStore.filters.publish_year === parsedYear) {
    searchStore.filters.publish_year = undefined
  } else {
    searchStore.filters.publish_year = parsedYear
    searchStore.filters.date_from = undefined
    searchStore.filters.date_to = undefined
  }
  searchStore.search(true)
}

function filterBySubjectWord(word: string) {
  const current = Array.isArray(searchStore.filters.subject_words)
    ? [...searchStore.filters.subject_words]
    : []
  const index = current.indexOf(word)

  if (index >= 0) {
    current.splice(index, 1)
  } else {
    current.push(word)
  }

  searchStore.filters.subject_words = current.length ? current : undefined
  searchStore.search(true)
}
</script>

<style scoped lang="less">
.search-view {
  padding: 24px 28px;

  .search-header {
    margin-bottom: 24px;
  }

  .result-header {
    margin-bottom: 16px;
    color: #595959;
    font-size: 14px;
    display: flex;
    align-items: center;
    gap: 12px;

    strong {
      color: #1890ff;
      font-size: 16px;
    }

    &__time {
      color: #bfbfbf;
      font-size: 12px;
    }
  }

  .selection-alert {
    margin-bottom: 16px;
    border-radius: 8px;
  }

  .basket-summary-card {
    margin-bottom: 16px;
    border-radius: 8px;
  }

  .basket-summary-card__count {
    margin-bottom: 12px;
    color: #595959;
  }

  .result-pagination {
    margin-top: 24px;
    text-align: center;
  }

  .permission-notice {
    margin-top: 20px;
    padding: 10px 16px;
    background: #f6f8fa;
    border: 1px solid #e8e8e8;
    border-radius: 6px;
    color: #8c8c8c;
    font-size: 12px;
    display: flex;
    align-items: center;
    gap: 8px;
    line-height: 1.6;
  }

  .sidebar-sticky {
    position: sticky;
    top: 64px;
    z-index: 10;
    background: #f5f5f5;
    padding-top: 12px;
  }

  .agg-card {
    position: sticky;
    top: 140px;
    border-radius: 8px;

    h4 {
      margin: 10px 0 6px;
      font-size: 13px;
      color: #8c8c8c;
      font-weight: 500;
    }

    .agg-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 5px 8px;
      margin: 0 -8px;
      cursor: pointer;
      font-size: 13px;
      border-radius: 4px;
      transition: all 0.15s;

      &:hover {
        color: #1890ff;
        background: #e6f7ff;
      }

      &--active {
        color: #1890ff;
        background: #e6f7ff;
        font-weight: 500;
      }

      .agg-label {
        flex: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        margin-right: 8px;
      }

      .agg-count {
        color: #1890ff;
        font-size: 12px;
        font-weight: 600;
        min-width: 28px;
        height: 20px;
        line-height: 20px;
        text-align: center;
        background: #e6f7ff;
        border-radius: 10px;
        padding: 0 6px;
      }
    }

    .agg-item--active .agg-count {
      color: #fff;
      background: #1890ff;
    }

    .agg-empty {
      text-align: center;
      color: #bfbfbf;
      font-size: 13px;
      padding: 16px 0;
    }
  }

  .empty-state,
  .initial-state {
    padding: 80px 0;
    text-align: center;
  }
}
</style>
