//! AI 事件监听与分发(分派器)— startListener / stopListener / handleEvent
//!
//! 拆分(批次 A-B1):14 个事件 case 按域拆到 3 个叶子 handler:
//!   - useAiStreamingEvents.handleStreamingEvent(流式)
//!   - useAiToolEvents.handleToolEvent(工具)
//!   - useAiLifecycleEvents.handleLifecycleEvent(生命周期)
//! 跨域共享的 helper/状态(textIdle/pendingMaxRounds/pendingDirAuths/pendingHelp、工具慢执行
//! 计时器、delta 去重 Map、flushCurrentText/friendlyError/notifyConversationChanged)已下沉到
//! aiShared 或 useAiPendingState(叶子)。依赖方向:分派器 → 各叶子 handler → aiShared / 叶子(无环)。
//!
//! handleEvent 保留外围逻辑(convId 同步/路由/看门狗)与 L2 状态机、跨端用户消息两个域内 handler。
//! useAiEvents() 返回 shape 保持不变(stores/ai.ts spread 形状不变 → 组件零改动)。

import { listen, emit } from '@tauri-apps/api/event'
import { aiApi } from '@/api'
import { useAppSettingsStore } from '@/stores/appSettings'
import { state } from '@/stores/ai'
import { nextMsgId, setConvState, convStates, switchingConvs, getConvStreamState, setConvCurrentText, setConvStreaming, clearConvStreamState, clearAllApprovalTimers, clearAllToolSlowTimers, flushCurrentText, friendlyError, notifyConversationChanged } from './aiShared'
import { resetStreamWatchdog, clearAllStreamWatchdogs } from './useAiStream'
import { setStreaming } from './streamingGuard'
import { loadConversations } from './useAiConversations'
import { handleStreamingEvent } from './useAiStreamingEvents'
import { handleToolEvent } from './useAiToolEvents'
import { handleLifecycleEvent } from './useAiLifecycleEvents'
import type { AiChatEvent, MessageId } from '@/api/types'

// 跨域共享 helper re-export(原为 useAiEvents 导出,拆分后从 aiShared/叶子透传,消费方 import 路径不变)
export { getConvState } from './aiShared'
export { flushCurrentText, friendlyError, notifyConversationChanged }
export { setContextCallbacks } from './useAiLifecycleEvents'
export type { ContextCallbacks } from './useAiLifecycleEvents'

let _unlistenAiEvent: (() => void) | null = null
let _unlistenConvChanged: (() => void) | null = null
// onStreamTimeout 广播的审批计时器清理事件 unlistener
let _unlistenApprovalClear: (() => void) | null = null
// startListener 并发去重:防 onMounted 与 sendMessage 首发竞态下重复注册 listener
// (两回调写同一 state.currentText → 流式文字双倍)
let _startPromise: Promise<void> | null = null

const appSettings = useAppSettingsStore()

// 看门狗不重置的事件集合(审批等待/完成/错误/达 max/路径授权/求助由各自 case 内 clear)。
// 模块级 Set 复用,避免每事件(delta/token 高频)新建数组字面量做 includes。
const NO_RESET_WATCHDOG = new Set<AiChatEvent['type']>(['AiApprovalRequired', 'AiCompleted', 'AiError', 'AiMaxRoundsReached', 'AiDirAuthRequired', 'AiHelpRequired'])

/** L2 状态机域:消费 AiConvStateChanged,写 convStates(per-conv conv_state 真相源)。
 *  返回 true=已处理;无 convId 无法路由时忽略(防误写全局态)。 */
function handleConvStateEvent(event: AiChatEvent): boolean {
  if (event.type !== 'AiConvStateChanged') return false
  const convId = event.conversation_id || state.activeConversationId
  if (!convId) return true
  setConvState(convId, event.conv_state)
  return true
}

/** 跨端用户消息域:miniapp→桌面 user 气泡同步(仅处理 AiUserMessage)。
 *  去重:末条已是同 content 的 user 则跳过(防本地乐观 push + 事件回灌双气泡)。 */
function handleUserMessageEvent(event: AiChatEvent): boolean {
  if (event.type !== 'AiUserMessage') return false
  // 多会话并行隔离:AiUserMessage 必带 conversation_id;非当前会话不污染当前视图,仅刷新列表
  const uc = event.conversation_id ?? null
  if (uc && state.activeConversationId && uc !== state.activeConversationId) {
    void loadConversations()
    return true
  }
  const last = state.messages[state.messages.length - 1]
  if (last && last.role === 'user' && last.content === event.message) {
    return true
  }
  state.messages.push({
    id: `user-${nextMsgId()}` as MessageId,
    role: 'user',
    content: event.message,
    timestamp: Date.now(),
  })
  return true
}

/** 后端事件分发:按 conversation_id 路由,流式累积文本,工具状态流转,看门狗联动 */
export function handleEvent(event: AiChatEvent) {
  const convId = event.conversation_id
  // 首次收到事件时同步当前对话 id(后端自动建对话的场景)并持久化
  if (convId && !state.activeConversationId) {
    state.activeConversationId = convId
    void appSettings.set('df-ai-active-conv', convId)
  }
  // L2 状态机:AiConvStateChanged 是 per-conv 状态信号,在 isCurrent 守卫之前处理
  // (切走会话时也须更新 conv_state,防停止按钮/MaxRoundsCard 错态)
  if (handleConvStateEvent(event)) return
  // 跨端用户消息同步:在 isCurrent 守卫之前处理(补 user 气泡信号,非流式活跃事件)
  if (handleUserMessageEvent(event)) return
  // 事件不属于当前展示对话(生成中切走了)→ 不污染当前视图,仅完成/错误/求助时刷新侧边栏
  const isCurrent = !convId || convId === state.activeConversationId
  if (!isCurrent) {
    if (event.type === 'AiCompleted' || event.type === 'AiError' || event.type === 'AiHelpRequired') {
      // 非当前会话终止:收敛会话状态(删 Map 项回不在生成)
      convStates.delete(convId || '')
      void loadConversations()
      // 后台会话终止也触发队列续发/清队(完成续发;错误清该会话队列)
      if (event.type === 'AiCompleted') {
        emit('ai-drain-queue', { conversationId: event.conversation_id })
      } else if (event.type === 'AiError') {
        if (event.conversation_id) {
          state.queue = state.queue.filter(q => q.conversationId !== event.conversation_id)
        } else {
          state.queue = []
        }
      }
    } else if (event.type === 'AiTextDelta' && convId && switchingConvs.has(convId)) {
      // 切换中缓冲:目标会话正被 switchConversation 拉取,其 delta 累积到 per-conv 流式态,
      // 切换完成后由渲染层续显,避免切换窗口丢可见内容
      setConvStreaming(convId, true)
      setConvCurrentText(convId, (getConvStreamState(convId)?.currentText ?? '') + (event.delta ?? ''))
    }
    return
  }
  // 无目标会话(事件缺 convId 且当前无活跃会话):流式 delta 无处累积,跳过写防 null 键无意义写入
  if (!convId && !state.activeConversationId && event.type === 'AiTextDelta') return
  // 活跃事件(delta/工具/新轮/审批结果)到达即标记该会话生成中(enum 兜底写入口;
  // 后端 AiConvStateChanged{generating} 已先到时同值 set 幂等覆盖,无副作用)
  if (convId && event.type !== 'AiCompleted' && event.type !== 'AiError' && event.type !== 'AiHelpRequired') {
    setConvState(convId, 'generating')
  }
  // 流式看门狗:活跃事件重置;审批等待/完成/错误在 case 内 clear(per-conv,各会话独立计时)
  if (!NO_RESET_WATCHDOG.has(event.type)) {
    resetStreamWatchdog(convId || undefined)
  }
  // 按域分派(streaming → tool → lifecycle);未命中任一域 → 无操作
  if (handleStreamingEvent(event)) return
  if (handleToolEvent(event)) return
  void handleLifecycleEvent(event)
}

/** 启动事件监听(幂等 + 并发去重,onMounted 与 sendMessage 首发竞态不会重复注册) */
export async function startListener() {
  if (_unlistenAiEvent && _unlistenConvChanged && _unlistenApprovalClear) {
    return
  }
  if (_startPromise) return _startPromise
  _startPromise = (async () => {
    try {
      _unlistenAiEvent = await aiApi.onEvent(handleEvent)
      _unlistenConvChanged = await listen('ai-conversation-changed', (e) => {
        void loadConversations()
        // 主窗口删除了本窗口当前展示的会话:清空视图防陈旧幽灵(分离窗口独立 JS context,经事件同步)。
        const deleted = (e.payload as { deletedConvId?: string } | undefined)?.deletedConvId
        if (deleted && state.activeConversationId === deleted) {
          state.activeConversationId = null
          state.messages = []
          clearConvStreamState(deleted)
          setStreaming(false, { convId: deleted, reason: 'conv-deleted' })
          convStates.delete(deleted)
        }
      })
      _unlistenApprovalClear = await listen('ai-approval-clear-timers', () => { clearAllApprovalTimers() })
      emit('ai-client-ready', { lastConvId: state.activeConversationId })
    } catch (err) {
      console.error('[useAiEvents] startListener 注册失败,事件监听未生效:', err)
      throw err
    }
  })()
  try {
    await _startPromise
  } finally {
    _startPromise = null
  }
}

/** 停止事件监听(卸载时调用,释放后端 listener + 清看门狗/计时器,防回调改已卸载组件 state) */
export function stopListener() {
  _unlistenAiEvent?.()
  _unlistenConvChanged?.()
  _unlistenApprovalClear?.()
  _unlistenAiEvent = null
  _unlistenConvChanged = null
  _unlistenApprovalClear = null
  // stop 清零去重 promise:极速 mount/unmount/mount(HMR)时,首 mount 的 _startPromise 可能仍 pending,
  // 再 mount 若命中并发去重分支会返回这个已代表「旧注册」的过期 promise,新 listener 实际未注册
  _startPromise = null
  clearAllStreamWatchdogs()
  clearAllToolSlowTimers()
  clearAllApprovalTimers()
}

export function useAiEvents() {
  return {
    startListener,
    stopListener,
    handleEvent,
    flushCurrentText,
    friendlyError,
    notifyConversationChanged,
  }
}
