/**
 * Notebook 模块 Pinia Store
 */

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type {
  Notebook,
  NotebookConfig,
  NotebookSource,
  NotebookMessage,
  NotebookOutput,
} from '@/types/notebook'
import type { QAReference } from '@/types/qa'
import * as api from '@/api/notebook'

export const useNotebookStore = defineStore('notebook', () => {
  // ── State ────────────────────────────────────────────
  const notebooks = ref<Notebook[]>([])
  const total = ref(0)
  const loading = ref(false)

  const currentNotebook = ref<Notebook | null>(null)
  const sources = ref<NotebookSource[]>([])
  const messages = ref<NotebookMessage[]>([])
  const outputs = ref<NotebookOutput[]>([])

  const isStreaming = ref(false)
  const currentAssistantContent = ref('')
  const references = ref<QAReference[]>([])
  const suggestions = ref<string[]>([])

  const isGeneratingOutput = ref(false)
  const currentOutputContent = ref('')

  // ── Computed ──────────────────────────────────────────
  const sourceCount = computed(() => sources.value.length)
  const maxSources = 10
  const completedSources = computed(() =>
    sources.value.filter((s) => s.ingest_status === 'completed'),
  )
  const selectedSources = computed(() =>
    sources.value.filter((s) => s.selected && s.ingest_status === 'completed'),
  )

  // ── Notebook CRUD ────────────────────────────────────

  async function loadNotebooks(params?: api.NotebookListParams) {
    loading.value = true
    try {
      const result = await api.listNotebooks(params)
      notebooks.value = result.items
      total.value = result.total
    } finally {
      loading.value = false
    }
  }

  async function loadNotebook(id: string) {
    currentNotebook.value = await api.getNotebook(id)
    sources.value = currentNotebook.value.sources || []
    // Load messages and outputs
    await Promise.all([loadChatHistory(id), loadOutputs(id)])
  }

  async function createNotebook(title: string, description = '') {
    const result = await api.createNotebook(title, description)
    return result.id
  }

  async function updateNotebook(id: string, body: {
    title?: string
    description?: string
    config?: NotebookConfig
  }) {
    await api.updateNotebook(id, body)
    if (currentNotebook.value?.id === id) {
      if (body.title) currentNotebook.value.title = body.title
      if (body.description !== undefined) currentNotebook.value.description = body.description
      if (body.config) currentNotebook.value.config = body.config
    }
  }

  async function deleteNotebook(id: string) {
    await api.deleteNotebook(id)
    notebooks.value = notebooks.value.filter((n) => n.id !== id)
    if (currentNotebook.value?.id === id) {
      currentNotebook.value = null
    }
  }

  // ── Sources ──────────────────────────────────────────

  async function refreshSources(notebookId: string) {
    const result = await api.listSources(notebookId)
    sources.value = result.items
  }

  async function addSourceBySearch(notebookId: string, docId: string, title?: string) {
    const result = await api.addSourceBySearch(notebookId, docId, title)
    await refreshSources(notebookId)
    return result
  }

  async function addSourceByUpload(notebookId: string, file: File) {
    const result = await api.addSourceByUpload(notebookId, file)
    await refreshSources(notebookId)
    return result
  }

  async function addSourceByPaste(notebookId: string, title: string, content: string) {
    const result = await api.addSourceByPaste(notebookId, title, content)
    await refreshSources(notebookId)
    return result
  }

  async function toggleSource(notebookId: string, sourceId: string, selected: boolean) {
    await api.updateSource(notebookId, sourceId, { selected })
    const src = sources.value.find((s) => s.id === sourceId)
    if (src) src.selected = selected
  }

  async function removeSource(notebookId: string, sourceId: string) {
    await api.deleteSource(notebookId, sourceId)
    sources.value = sources.value.filter((s) => s.id !== sourceId)
  }

  async function retrySource(notebookId: string, sourceId: string) {
    await api.retrySourceIngest(notebookId, sourceId)
    const src = sources.value.find((s) => s.id === sourceId)
    if (src) {
      src.ingest_status = 'pending'
      src.ingest_error = undefined
    }
  }

  // ── Chat ─────────────────────────────────────────────

  async function loadChatHistory(notebookId: string) {
    try {
      const result = await api.getChatHistory(notebookId)
      messages.value = result.messages
      // Load suggestions from last assistant message
      const lastAssistant = [...result.messages].reverse().find((m) => m.role === 'assistant')
      if (lastAssistant?.suggestions) {
        suggestions.value = lastAssistant.suggestions
      }
      // Load references from last assistant message
      if (lastAssistant?.references) {
        references.value = lastAssistant.references
      }
    } catch {
      messages.value = []
    }
  }

  function startStreaming() {
    isStreaming.value = true
    currentAssistantContent.value = ''
    references.value = []
  }

  function appendStreamChunk(text: string) {
    currentAssistantContent.value += text
  }

  function addReference(ref_: QAReference) {
    // Notebook mode: keep all passage-level refs (same doc_id, different passages)
    // so [1][2][3] from the same doc each have a matching entry
    references.value.push(ref_)
  }

  function setSuggestions(items: string[]) {
    suggestions.value = items
  }

  function finishStreaming(notebookId: string) {
    if (!isStreaming.value) return // Idempotent guard
    if (currentAssistantContent.value) {
      messages.value.push({
        id: `local_${Date.now()}`,
        role: 'assistant',
        content: currentAssistantContent.value,
        references: [...references.value],
        suggestions: [...suggestions.value],
        created_at: new Date().toISOString(),
      })
    }
    isStreaming.value = false
    currentAssistantContent.value = ''
  }

  function addUserMessage(content: string) {
    messages.value.push({
      id: `local_${Date.now()}`,
      role: 'user',
      content,
      created_at: new Date().toISOString(),
    })
  }

  async function loadSuggestions(notebookId: string) {
    try {
      const result = await api.getSuggestions(notebookId)
      suggestions.value = result.suggestions
    } catch {
      suggestions.value = []
    }
  }

  // ── Outputs ──────────────────────────────────────────

  async function loadOutputs(notebookId: string) {
    try {
      const result = await api.listOutputs(notebookId)
      outputs.value = result.items
    } catch {
      outputs.value = []
    }
  }

  async function loadOutput(notebookId: string, outputId: string): Promise<NotebookOutput> {
    return await api.getOutput(notebookId, outputId)
  }

  async function removeOutput(notebookId: string, outputId: string) {
    await api.deleteOutput(notebookId, outputId)
    outputs.value = outputs.value.filter((o) => o.id !== outputId)
  }

  function startOutputGeneration() {
    isGeneratingOutput.value = true
    currentOutputContent.value = ''
  }

  function appendOutputChunk(text: string) {
    currentOutputContent.value += text
  }

  function finishOutputGeneration() {
    isGeneratingOutput.value = false
    currentOutputContent.value = ''
  }

  return {
    // State
    notebooks,
    total,
    loading,
    currentNotebook,
    sources,
    messages,
    outputs,
    isStreaming,
    currentAssistantContent,
    references,
    suggestions,
    isGeneratingOutput,
    currentOutputContent,

    // Computed
    sourceCount,
    maxSources,
    completedSources,
    selectedSources,

    // Actions
    loadNotebooks,
    loadNotebook,
    createNotebook,
    updateNotebook,
    deleteNotebook,

    refreshSources,
    addSourceBySearch,
    addSourceByUpload,
    addSourceByPaste,
    toggleSource,
    removeSource,
    retrySource,

    loadChatHistory,
    startStreaming,
    appendStreamChunk,
    addReference,
    setSuggestions,
    finishStreaming,
    addUserMessage,
    loadSuggestions,

    loadOutputs,
    loadOutput,
    removeOutput,
    startOutputGeneration,
    appendOutputChunk,
    finishOutputGeneration,
  }
})
