//! F-15 手动上下文管理 — 清空 / 压缩
//!
//! 职责:
//! - clearContext():二次确认 → aiApi.clearContext(activeConversationId)
//! - compressContext():aiApi.compressContext(activeConversationId, locale)
//!   + isCompressing ref(loading,防重复点击)
//! - initContextListener:注入生命周期回调到 useAiEvents 统一分发器
//!   (原独立第二监听器已删除,治本:一个事件源→一个监听器→一个分发器)
//!
//! 事件由 useAiEvents.handleLifecycleEvent 统一处理:
//!   AiCompressing        → onCompressing(isCompressing=true)
//!   AiManualCompressed   → onManualCompressed(isCompressing=false + toast + 摘要回填)
//!   AiAutoCompressed     → onAutoCompressed(isCompressing=false,静默不弹 toast)
//!   AiContextCleared     → onCleared(toast + 刷新)
//!   AiError              → onError(仅在 isCompressing 时复位 loading + toast)
//!
//! 耦合:
//! - aiApi.clearContext / aiApi.compressContext(IPC)
//! - state.activeConversationId(读当前对话)
//! - resolveAiLang(压缩语言;与 useAiSend.sendMessage 同源,实现在 aiShared)

import { ref } from 'vue'
import { aiApi } from '@/api'
import { state } from '@/stores/ai'
import { resolveAiLang } from './aiShared'
import { setContextCallbacks } from './useAiEvents'

/// 压缩中 loading(防重复点击;AiCompressing→true / AiManualCompressed|AiAutoCompressed|AiError→false)
const isCompressing = ref(false)

/**
 * 注入上下文生命周期回调到统一事件分发器(幂等)。
 *
 * AiChat.vue onMounted 调一次,注入 toast/刷新副作用回调。
 * 事件由 useAiEvents 统一监听与分发(原独立第二监听器已删除)。
 */
async function initContextListener(callbacks: {
  onCleared?: (conversationId: string) => void
  onCompressed?: (conversationId: string, summary: string) => void
  onError?: (conversationId: string, message: string) => void
}): Promise<void> {
  setContextCallbacks({
    onCompressing: () => { isCompressing.value = true },
    onManualCompressed: (convId, summary) => {
      isCompressing.value = false
      callbacks.onCompressed?.(convId, summary)
    },
    onAutoCompressed: () => {
      // loop 自动压缩静默——仅复位 loading(冗余兜底,Auto 路径前端 loading 本就 false)
      isCompressing.value = false
    },
    onCleared: (convId) => callbacks.onCleared?.(convId),
    onError: (convId, message) => {
      // AiError 也用于流式生成失败(useAiEvents 已处理);此处仅在压缩中时复位 + toast,
      // 避免双重处理流式错误。
      if (isCompressing.value) {
        isCompressing.value = false
        callbacks.onError?.(convId, message)
      }
    },
  })
}

/** 释放回调(AiChat.vue onBeforeUnmount 调) */
function stopContextListener(): void {
  setContextCallbacks({})
}

/**
 * 压缩当前对话上下文。
 *
 * 失败兜底:IPC 未送达(spawn 前/provider 配置错)由 catch 回滚 isCompressing + 抛错,
 * 让调用方弹错误 toast;后端处理失败走 AiError 事件 → 分发器复位 + onError。
 *
 * @throws IPC 失败时抛出原错(调用方 toast)
 */
async function compressContext(): Promise<void> {
  const convId = state.activeConversationId
  if (!convId) return
  if (isCompressing.value) return // 防重复点击
  isCompressing.value = true
  try {
    await aiApi.compressContext(convId, resolveAiLang())
    // 后端 IPC 同步等到 LLM 压缩完成才 resolve(非 spawn 异步),成功即复位 isCompressing;
    // AiManualCompressed 事件也复位(双保险,防事件丢失致按钮永久禁用)
    isCompressing.value = false
  } catch (e) {
    isCompressing.value = false
    throw e
  }
}

/**
 * 清空当前对话上下文(仅触发 IPC,二次确认由调用方 AiChat.vue 弹)。
 *
 * @throws IPC 失败时抛出原错(调用方 toast)
 */
async function clearContext(): Promise<void> {
  const convId = state.activeConversationId
  if (!convId) return
  await aiApi.clearContext(convId)
}

export function useAiContext() {
  return {
    // 状态
    isCompressing,
    // 操作
    clearContext,
    compressContext,
    // 生命周期
    initContextListener,
    stopContextListener,
  }
}
