//! 流式看门狗 — 无数据超时兜底
//!
//! 后端断连/异常不发 AiCompleted/AiError 时,前端自动收尾+提示,
//! 避免 streaming 永久 true 卡死对话(用户报"流式文字停在中途"即此类)。
//!
//! 耦合说明:
//! - sendMessage 启动生成时 resetStreamWatchdog() 启动计时
//! - handleEvent 每个活跃事件(delta/工具/新轮/审批结果)重置;审批等待/完成/错误 clear
//! - 超时回调 onStreamTimeout 直接改 state 并补一条错误消息
//!
//! 依赖:nextMsgId 取自 aiShared(原从 useAiEvents 取,构成 useAiEvents ↔ useAiStream
//! 循环依赖;下沉到 aiShared 后本模块不再 import useAiEvents,环消除)

import { state } from '@/stores/ai'
import { t } from '@/i18n/i18n-helpers'
import { nextMsgId } from './aiShared'
import { emit } from '@tauri-apps/api/event'

/// ≥ 后端 STREAM_IDLE_TIMEOUT(120s, ai.rs:848)+余量;
/// 前端若短于后端,慢首 token 会被前端先误杀
export const STREAM_TIMEOUT_MS = 130000

let _streamWatchdog: ReturnType<typeof setTimeout> | null = null

/** 看门狗超时回调:收尾 streaming 态并补错误消息 */
export function onStreamTimeout() {
  state.streaming = false
  state.generatingConvId = null
  state.currentText = ''
  state.queue = [] // B-32:超时收尾同步清队列,防生成中入队的消息静默丢失
  clearStreamWatchdog()
  // AE-2025-06: 整流超时收尾 → 广播清全部审批超时计时器。
  // 本模块不 import useAiSend(会构成 useAiSend↔useAiStream 循环依赖,与现有破环原则冲突),
  // 复用 ai-tool-slow-toast 同款事件总线模式:emit 由 useAiEvents.startListener listen 后调
  // clearAllApprovalTimers。流式已中断,审批继续挂定时器无意义(用户也会随之停止交互)。
  void emit('ai-approval-clear-timers', {})
  // 一次性遍历同时做两件事(单次 O(n),不再分两遍扫):
  // 1) 回滚 running 态工具调用 → rejected:approveToolCall 已不乐观置 running(B-260616-08),
  //    此分支兜底后端事件先转 running 再 hang 的卡片,避免永久骨架屏。B-260615-07/B-33 残留。
  //    (approve 后无 running 转换而 hang 的卡片由 ToolCard 本地 approving 计时器兜底复位,
  //     不在此全局回滚 pending_approval——会误伤其他真正待审批的卡片。)
  // 2) 探测任一 completed 卡片以区分错误文案(工具已执行完后续回复中断 vs 纯流式中断)。
  // 反向扫尾部提前退出(同 findToolCall 策略);不复用 useAiEvents.findToolCall:本模块
  // 不依赖 useAiEvents(已下沉 nextMsgId 到 aiShared 破环),且此处需全量回滚而非按 id 定位。
  let hasCompletedTool = false
  for (let i = state.messages.length - 1; i >= 0; i--) {
    const toolCalls = state.messages[i].toolCalls
    if (!toolCalls) continue
    for (let j = 0; j < toolCalls.length; j++) {
      const tc = toolCalls[j]
      if (tc.status === 'running') {
        // B-33:running 态无后续事件回流,置 rejected 释放骨架屏,恢复重审入口
        tc.status = 'rejected'
      } else if (tc.status === 'completed') {
        hasCompletedTool = true
      }
    }
  }
  const content = hasCompletedTool
    ? t('ai.streamInterruptedAfterTool')
    : t('ai.streamInterrupted')
  state.messages.push({
    id: `timeout-${nextMsgId()}`,
    role: 'assistant',
    content,
    isError: true,
    timestamp: Date.now(),
  })
}

/** 启动/重置看门狗(活跃事件或 sendMessage 时调用) */
export function resetStreamWatchdog() {
  if (_streamWatchdog) clearTimeout(_streamWatchdog)
  _streamWatchdog = setTimeout(onStreamTimeout, STREAM_TIMEOUT_MS)
}

/** 清除看门狗(完成/错误/审批等待时调用) */
export function clearStreamWatchdog() {
  if (_streamWatchdog) { clearTimeout(_streamWatchdog); _streamWatchdog = null }
}

export function useAiStream() {
  return {
    onStreamTimeout,
    resetStreamWatchdog,
    clearStreamWatchdog,
  }
}
