import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import * as kbApi from '@/api/kb'
import type {
  IKbSource,
  ISearchResult,
  IUploadedDocument,
  IPreviewResult,
  IKBSettings,
  IKBSettingsUpdate,
} from '@/api/kb'

/**
 * Default KB id used for KB-level settings.
 *
 * ponytail: the frontend has no KB selector UI; the settings endpoint
 * keys on an arbitrary ``kb_id`` string. Using a single "default" KB is
 * the smallest thing that works. Upgrade path: add a KB picker when
 * multiple KBs are exposed.
 */
export const DEFAULT_KB_ID = 'default'

/** Terminal document statuses (no further polling needed). */
const TERMINAL_STATUSES = new Set(['indexed', 'failed'])

export const useKnowledgeStore = defineStore('knowledge', () => {
  // --- State ---
  const sources = ref<IKbSource[]>([])
  const documents = ref<IUploadedDocument[]>([])
  const searchResults = ref<ISearchResult[]>([])
  const isLoading = ref(false)
  const isUploading = ref(false)
  const isSearching = ref(false)
  const isPreviewing = ref(false)
  const previewResult = ref<IPreviewResult | null>(null)
  const kbSettings = ref<IKBSettings | null>(null)
  const isSavingSettings = ref(false)
  const error = ref<string | null>(null)

  // --- Getters ---
  const sourceCount = computed(() => sources.value.length)
  const localSources = computed(() => sources.value.filter((s) => s.type === 'local'))
  const externalSources = computed(() => sources.value.filter((s) => s.type !== 'local'))
  /** Documents still being processed (non-terminal) — drives status polling. */
  const processingDocuments = computed(() =>
    documents.value.filter((d) => !TERMINAL_STATUSES.has(d.status)),
  )

  // --- Actions ---
  async function fetchSources(): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      const data = await kbApi.listSources()
      sources.value = data.sources
    } catch (err) {
      error.value = err instanceof Error ? err.message : '获取信息源列表失败'
      console.error('Failed to fetch sources:', err)
    } finally {
      isLoading.value = false
    }
  }

  async function addSource(
    name: string,
    type: 'local' | 'feishu' | 'confluence' | 'http',
    config: Record<string, unknown> = {}
  ): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      await kbApi.addSource({ name, type, config })
      await fetchSources()
    } catch (err) {
      error.value = err instanceof Error ? err.message : '添加信息源失败'
      console.error('Failed to add source:', err)
      throw err
    } finally {
      isLoading.value = false
    }
  }

  async function removeSource(sourceId: string): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      await kbApi.removeSource(sourceId)
      await fetchSources()
    } catch (err) {
      error.value = err instanceof Error ? err.message : '删除信息源失败'
      console.error('Failed to remove source:', err)
      throw err
    } finally {
      isLoading.value = false
    }
  }

  async function uploadDocument(file: File, sourceId?: string): Promise<IUploadedDocument> {
    isUploading.value = true
    error.value = null
    try {
      const data = await kbApi.uploadDocument(file, sourceId)
      await fetchSources()
      return data
    } catch (err) {
      error.value = err instanceof Error ? err.message : '上传文档失败'
      console.error('Failed to upload document:', err)
      throw err
    } finally {
      isUploading.value = false
    }
  }

  async function search(query: string, sourceIds?: string[], topK: number = 5, strategy: string = 'vector'): Promise<void> {
    isSearching.value = true
    error.value = null
    searchResults.value = []
    try {
      const data = await kbApi.searchKnowledge(query, sourceIds, topK, strategy)
      searchResults.value = data.results
    } catch (err) {
      error.value = err instanceof Error ? err.message : '检索失败'
      console.error('Failed to search:', err)
    } finally {
      isSearching.value = false
    }
  }

  async function checkHealth(sourceId: string): Promise<string> {
    try {
      const data = await kbApi.checkSourceHealth(sourceId)
      return data.status
    } catch (err) {
      console.error('Failed to check health:', err)
      return 'error'
    }
  }

  async function fetchDocuments(sourceId?: string): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      const data = await kbApi.listDocuments(sourceId)
      documents.value = data.documents
    } catch (err) {
      error.value = err instanceof Error ? err.message : '获取文档列表失败'
      console.error('Failed to fetch documents:', err)
    } finally {
      isLoading.value = false
    }
  }

  async function deleteDocument(documentId: string): Promise<void> {
    try {
      await kbApi.deleteDocument(documentId)
      documents.value = documents.value.filter((d) => d.document_id !== documentId)
      await fetchSources()
    } catch (err) {
      error.value = err instanceof Error ? err.message : '删除文档失败'
      console.error('Failed to delete document:', err)
      throw err
    }
  }

  async function syncSource(sourceId: string): Promise<string> {
    try {
      const data = await kbApi.syncSource(sourceId)
      return data.status
    } catch (err) {
      error.value = err instanceof Error ? err.message : '同步失败'
      console.error('Failed to sync source:', err)
      throw err
    }
  }

  async function updateSource(sourceId: string, data: Partial<{ name: string; type: 'local' | 'feishu' | 'confluence' | 'http'; config: Record<string, unknown> }>): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      await kbApi.updateSource(sourceId, data)
      await fetchSources()
    } catch (err) {
      error.value = err instanceof Error ? err.message : '更新信息源失败'
      console.error('Failed to update source:', err)
      throw err
    } finally {
      isLoading.value = false
    }
  }

  /** Preview segmentation for a file without persisting (read-only). */
  async function previewDocument(
    file: File,
    chunkSize: number = 512,
    chunkOverlap: number = 50,
  ): Promise<IPreviewResult> {
    isPreviewing.value = true
    error.value = null
    previewResult.value = null
    try {
      const data = await kbApi.previewDocument(file, chunkSize, chunkOverlap)
      previewResult.value = data
      return data
    } catch (err) {
      error.value = err instanceof Error ? err.message : '分段预览失败'
      console.error('Failed to preview document:', err)
      throw err
    } finally {
      isPreviewing.value = false
    }
  }

  /** Clear the preview result (when closing the preview modal). */
  function clearPreview(): void {
    previewResult.value = null
  }

  /**
   * Retry vectorization for a failed document.
   *
   * ponytail: the backend vectorize endpoint currently returns 503
   * (requires PG-backed KBStore, U8). The frontend still attempts the
   * call so that once the backend lands, retry works without changes.
   * Upgrade path: backend implements async vectorization + status push.
   */
  async function retryDocument(documentId: string): Promise<void> {
    try {
      await kbApi.vectorizeDocument(documentId)
      await fetchDocuments()
    } catch (err) {
      error.value = err instanceof Error ? err.message : '重试向量化失败'
      console.error('Failed to retry vectorization:', err)
      throw err
    }
  }

  /** Fetch KB-level settings for the given KB (defaults to the single KB). */
  async function fetchKbSettings(kbId: string = DEFAULT_KB_ID): Promise<void> {
    isLoading.value = true
    error.value = null
    try {
      kbSettings.value = await kbApi.getKbSettings(kbId)
    } catch (err) {
      error.value = err instanceof Error ? err.message : '获取 KB 设置失败'
      console.error('Failed to fetch KB settings:', err)
    } finally {
      isLoading.value = false
    }
  }

  /** Update KB-level settings (owner only). */
  async function saveKbSettings(
    update: IKBSettingsUpdate,
    kbId: string = DEFAULT_KB_ID,
  ): Promise<void> {
    isSavingSettings.value = true
    error.value = null
    try {
      kbSettings.value = await kbApi.updateKbSettings(kbId, update)
    } catch (err) {
      error.value = err instanceof Error ? err.message : '保存 KB 设置失败'
      console.error('Failed to save KB settings:', err)
      throw err
    } finally {
      isSavingSettings.value = false
    }
  }

  return {
    // State
    sources,
    documents,
    searchResults,
    isLoading,
    isUploading,
    isSearching,
    isPreviewing,
    previewResult,
    kbSettings,
    isSavingSettings,
    error,
    // Getters
    sourceCount,
    localSources,
    externalSources,
    processingDocuments,
    // Actions
    fetchSources,
    addSource,
    removeSource,
    uploadDocument,
    search,
    checkHealth,
    fetchDocuments,
    deleteDocument,
    syncSource,
    updateSource,
    previewDocument,
    clearPreview,
    retryDocument,
    fetchKbSettings,
    saveKbSettings,
  }
})
