//! 工具调用审计记录写/回填(audit_tool_call 写入 + audit_finalize 审批后状态回填)
//!
//! 第二批从 audit/mod.rs 抽出(行为零变更,纯 fn 搬迁)。re-export 经 audit/mod.rs
//! `pub use finalize::{audit_tool_call, audit_finalize};` 保持 `commands::ai::audit::*`
//! 路径透明(调用方零变更)。

use df_ai::ai_tools::RiskLevel;
use df_storage::crud::AiToolExecutionRepo;
use df_storage::models::AiToolExecutionRecord;

use df_types::types::new_id;

use crate::commands::now_millis;
use crate::state::AppState;

use super::risk_str;

/// 写一条工具执行审计记录（insert 失败不阻断主流程，故 `let _ =`）
///
/// `decided_by` 有值（auto/human）= 已决策执行 → 记 executed_at；
/// `None`（pending 待审批）→ executed_at 留空，待 audit_finalize 回填。
pub(crate) async fn audit_tool_call(
    repo: &AiToolExecutionRepo,
    conv_id: &str,
    tool_call_id: &str,
    tool_name: &str,
    arguments: &str,
    status: &str,
    risk_level: RiskLevel,
    result: Option<String>,
    decided_by: Option<&str>,
    message_id: Option<&str>,
) {
    let executed_at = if decided_by.is_some() { Some(now_millis()) } else { None };
    let _ = repo
        .insert(AiToolExecutionRecord {
            id: new_id(),
            conversation_id: Some(conv_id.to_string()),
            // F-260619-04 P1 消息级溯源:message_id 由调用方(process_tool_calls)从
            // ContextManager 取当前 assistant 消息 id 传入(LLM 返回带 tool_calls 的
            // assistant 消息已 push 到 per_conv.messages,入口取末条 assistant id)。
            // None 表示无 assistant 消息(异常路径/老数据无 id),展示侧兼容。
            message_id: message_id.map(|s| s.to_string()),
            tool_call_id: tool_call_id.to_string(),
            tool_name: tool_name.to_string(),
            arguments: arguments.to_string(),
            result,
            status: status.to_string(),
            risk_level: risk_str(risk_level).to_string(),
            requested_at: now_millis(),
            executed_at,
            decided_by: decided_by.map(|s| s.to_string()),
        })
        .await;
}

/// 审批后更新审计记录状态（按 tool_call_id 定位 pending 记录，回填 status/decided_by=human/executed_at/result）
///
/// 走专用 find_by_tool_call_id —— 通用 query 宏硬编码 ORDER BY created_at DESC，
/// 而 ai_tool_executions 无该列，调用会报 "no such column: created_at" 被 unwrap_or_default 吞掉，
/// 导致审批后审计记录永久卡 pending。
pub(crate) async fn audit_finalize(state: &AppState, tool_call_id: &str, status: &str, result: Option<String>) {
    // 区分 Err(DB 故障)与 Ok(None)(真无记录):原 unwrap_or_default 把 Err 压成 None,
    // DB 故障被「未找到」日志掩盖,审批后审计记录卡 pending 无确诊线索(B-260617-17 同款吞错)。
    let mut rec = match state.ai_tool_executions.find_by_tool_call_id(tool_call_id).await {
        Ok(Some(rec)) => rec,
        Ok(None) => {
            tracing::warn!("audit_finalize: 未找到 tool_call_id={} 的审计记录", tool_call_id);
            return;
        }
        Err(e) => {
            tracing::error!("audit_finalize: 查询 tool_call_id={} 审计记录失败(DB 故障,状态未回填): {}", tool_call_id, e);
            return;
        }
    };
    rec.status = status.to_string();
    rec.decided_by = Some("human".to_string());
    rec.executed_at = Some(now_millis());
    if let Some(r) = result {
        rec.result = Some(r);
    }
    if let Err(e) = state.ai_tool_executions.update_full(&rec).await {
        tracing::error!("audit_finalize: 回填 tool_call_id={} 审计状态失败: {}", tool_call_id, e);
    }
}
