import { ref, computed } from 'vue'
import {
  streamChat,
  listSessions,
  getHistory,
  deleteSession,
  listTools,
  type AssistantSessionMeta
} from '@/api/assistant'

export interface ToolInvocation {
  name: string
  isWrite: boolean
  args?: unknown
  status: 'running' | 'ok' | 'error'
  result?: unknown
}

export interface ChatMessage {
  id: string
  role: 'user' | 'assistant'
  content: string
  tools: ToolInvocation[]
  streaming?: boolean
  error?: string | null
}

const CURRENT_KEY = 'assistant.currentSessionId'

function uid(): string {
  return (globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2)}`)
}

/**
 * AI 助手对话状态机：维护消息列表 + 会话列表，封装发送/中断/历史加载/会话切换。
 * 单例式（模块级状态），让抽屉在路由切换后仍保留当前对话。
 */
const messages = ref<ChatMessage[]>([])
const sessions = ref<AssistantSessionMeta[]>([])
const currentSessionId = ref<string | null>(localStorage.getItem(CURRENT_KEY))
const status = ref<'idle' | 'streaming'>('idle')
const toolIsWrite = ref<Record<string, boolean>>({})
let initialized = false
let abort: AbortController | null = null

const isStreaming = computed(() => status.value === 'streaming')
const canSend = computed(() => status.value === 'idle')

function persistCurrent(): void {
  try {
    if (currentSessionId.value) localStorage.setItem(CURRENT_KEY, currentSessionId.value)
    else localStorage.removeItem(CURRENT_KEY)
  } catch {
    /* ignore */
  }
}

async function refreshSessions(): Promise<void> {
  try {
    sessions.value = await listSessions()
  } catch {
    /* 列表失败不阻塞对话 */
  }
}

async function ensureInit(): Promise<void> {
  if (initialized) return
  initialized = true
  try {
    const tools = await listTools()
    const map: Record<string, boolean> = {}
    for (const t of tools) map[t.name] = t.isWrite
    toolIsWrite.value = map
  } catch {
    /* 工具清单失败：tool 卡片仍可展示，仅缺少读写标识 */
  }
  await refreshSessions()
  if (currentSessionId.value) await loadSession(currentSessionId.value)
}

async function loadSession(id: string): Promise<void> {
  if (status.value === 'streaming') return
  try {
    const h = await getHistory(id)
    const list: ChatMessage[] = []
    const turns = h.turns ?? []
    for (let i = 0; i < turns.length; i++) {
      const t = turns[i]
      if (t.role === 'user') {
        list.push({ id: uid(), role: 'user', content: t.content ?? '', tools: [] })
      } else if (t.role === 'assistant') {
        const tools: ToolInvocation[] = []
        const calls = t.toolCalls ?? []
        for (const c of calls) {
          // 历史中工具结果是紧随其后的 tool 轮，按顺序取回。
          let result: unknown
          const next = turns[i + 1]
          if (next && next.role === 'tool') {
            try {
              result = JSON.parse(next.content ?? 'null')
            } catch {
              result = next.content
            }
            i++
          }
          let args: unknown
          try {
            args = JSON.parse(c.arguments || '{}')
          } catch {
            args = c.arguments
          }
          tools.push({ name: c.name, isWrite: toolIsWrite.value[c.name] ?? false, args, status: 'ok', result })
        }
        list.push({ id: uid(), role: 'assistant', content: t.content ?? '', tools })
      }
      // 落单的 tool 轮（理论上已被上面消费）跳过。
    }
    messages.value = list
    currentSessionId.value = id
    persistCurrent()
  } catch {
    /* ignore */
  }
}

function newSession(): void {
  if (status.value === 'streaming') stop()
  messages.value = []
  currentSessionId.value = null
  persistCurrent()
}

async function removeSession(id: string): Promise<void> {
  try {
    await deleteSession(id)
  } catch {
    /* ignore */
  }
  await refreshSessions()
  if (currentSessionId.value === id) newSession()
}

async function send(text: string): Promise<void> {
  const msg = text.trim()
  if (!msg || status.value === 'streaming') return

  messages.value.push({ id: uid(), role: 'user', content: msg, tools: [] })
  const assistant: ChatMessage = { id: uid(), role: 'assistant', content: '', tools: [], streaming: true, error: null }
  messages.value.push(assistant)
  status.value = 'streaming'
  abort = new AbortController()

  await streamChat(
    { message: msg, sessionId: currentSessionId.value, profile: 'analysis' },
    {
      onSession: (sid) => {
        if (sid) {
          currentSessionId.value = sid
          persistCurrent()
        }
      },
      onToken: (delta) => {
        assistant.content += delta
      },
      onToolCall: (name, args) => {
        assistant.tools.push({ name, isWrite: toolIsWrite.value[name] ?? false, args, status: 'running' })
      },
      onToolResult: (name, ok, result) => {
        const card = [...assistant.tools].reverse().find((t) => t.name === name && t.status === 'running')
        if (card) {
          card.status = ok ? 'ok' : 'error'
          card.result = result
        } else {
          assistant.tools.push({ name, isWrite: toolIsWrite.value[name] ?? false, status: ok ? 'ok' : 'error', result })
        }
      },
      onError: (message) => {
        assistant.error = message
      },
      onDone: () => {
        assistant.streaming = false
        status.value = 'idle'
        abort = null
        void refreshSessions()
      }
    },
    abort.signal
  )

  // 兜底：若流意外结束未触发 done。
  if (assistant.streaming) {
    assistant.streaming = false
    status.value = 'idle'
    abort = null
  }
}

function stop(): void {
  if (abort) {
    abort.abort()
    abort = null
  }
  const last = messages.value[messages.value.length - 1]
  if (last && last.role === 'assistant' && last.streaming) {
    last.streaming = false
    if (!last.content && last.tools.length === 0) last.content = '（已停止）'
  }
  status.value = 'idle'
}

export function useAssistantChat() {
  return {
    messages,
    sessions,
    currentSessionId,
    status,
    isStreaming,
    canSend,
    ensureInit,
    refreshSessions,
    loadSession,
    newSession,
    removeSession,
    send,
    stop
  }
}
