//! B-260615-09: generating 状态 RAII guard —— 从 agentic.rs 抽离(重构第一批,纯结构搬迁)。
//!
//! 行为零变更:仅文件位置移动,逻辑/字段/语义完全保留。
//! 调用方(agentic.rs run_agentic_loop)经 `use super::guard::GeneratingGuard;` 复用。

use std::sync::Arc;

use tokio::sync::Mutex;

use crate::commands::ai::AiSession;

/// generating 复位 RAII guard,取代散布的手动 `session.generating = false`。
///
/// 两路复位:
/// - 正常路径:exit 点显式 `reset().await` 即时复位(emit 前调,保证"复位→emit"顺序,
///   前端收事件时后端已可接下一条)。
/// - 异常路径(panic/未走正常 return):Drop 兜底 spawn 复位,防 generating 永真卡死前端。
///
/// 注:try_continue_agent_loop 不用 guard——其 should_continue=false 路径需保持
/// generating=true(审批等待态),全函数 guard 会误复位;该函数单点 provider-Err 复位保持手动。
///
/// F-260616-09 B 批2:guard 持 `conv_id`,复位改写 `session.conv(&conv_id).generating = false`
/// (per-conv 真相源)。同时**双写顶层 `session.generating = false`** 作共存期桥接 —— 批2
/// 仅迁移 agentic.rs 路径,IPC(ai_is_generating/ai_chat_send)仍读顶层,故 guard 须双写
/// 保证 IPC 读到正确值(否则前端 ai_is_generating 永远 true 卡死发送)。批4 IPC 迁移后
/// 顶层双写移除。
pub(super) struct GeneratingGuard {
    session: Arc<Mutex<AiSession>>,
    /// guard 所属会话(loop 启动时快照的 conv_id,来自 run_agentic_loop 入参)。
    conv_id: String,
    done: bool,
}

impl GeneratingGuard {
    pub(super) fn new(session: Arc<Mutex<AiSession>>, conv_id: String) -> Self {
        Self { session, conv_id, done: false }
    }

    /// 显式复位 generating=false。emit 前调用保证顺序。幂等。
    ///
    /// 双写:per_conv.conv_id.generating(新真相源)+ 顶层 generating(共存期 IPC 桥接)。
    pub(super) async fn reset(&mut self) {
        if !self.done {
            let mut session = self.session.lock().await;
            session.conv(&self.conv_id).generating = false;
            self.done = true;
        }
    }

    /// 解除 Drop 兜底复位但不复位 generating。审批等待 return 路径调用:
    /// 保持 generating=true 留 try_continue 续生成,同时 Drop 因 done=true 跳过复位 spawn。
    /// (B-260615-26: 修复审批执行后对话不续生成回归)
    pub(super) fn disarm(&mut self) {
        self.done = true;
    }
}

impl Drop for GeneratingGuard {
    fn drop(&mut self) {
        if !self.done {
            let session = self.session.clone();
            let conv_id = self.conv_id.clone();
            tauri::async_runtime::spawn(async move {
                let mut s = session.lock().await;
                s.conv(&conv_id).generating = false;
            });
        }
    }
}
