/**
 * Tool Guard — 工具调用安全守卫
 *
 * 在每次工具执行前进行安全检查，优先级高于所有用户权限模式。
 * 双层检测：正则规则（快速）→ LLM 审查（兜底）
 */

import { evaluateRules } from './rules.js';
import { reviewWithLLM } from './llm-reviewer.js';
import { DATA_DIR, getUserPaths } from '../user-directories.js';
import path from 'path';

const VERBOSE = process.env.TOOL_GUARD_VERBOSE === 'true';

/**
 * 将工具输入中的 .claude 路径重写为用户专属 claudeDir
 *
 * 处理以下模式（以便多用户环境下正确访问技能、配置等）：
 *   ~/.claude/...      → claudeDir/...
 *   $HOME/.claude/...  → claudeDir/...
 *   ./.claude/...      → claudeDir/...（相对路径，常见于技能脚本调用）
 *
 * @param {string} toolName
 * @param {Record<string, unknown>} input
 * @param {string} claudeDir - 用户的 .claude 绝对路径
 * @returns {Record<string, unknown>|null} 有改动时返回新 input 对象，否则返回 null
 */
function rewriteClaudePaths(toolName, input, claudeDir) {
  if (!input || !claudeDir) return null;

  function replaceInStr(str) {
    if (!str || typeof str !== 'string') return str;
    let s = str;
    // ~/.claude
    s = s.replace(/~\/\.claude(\/|$)/g, `${claudeDir}$1`);
    // $HOME/.claude
    s = s.replace(/\$HOME\/\.claude(\/|$)/g, `${claudeDir}$1`);
    // ./.claude（前面是行首、空白或引号）
    s = s.replace(/(^|[\s"'])\.\/\.claude(\/|$)/g, `$1${claudeDir}$2`);
    return s;
  }

  const newInput = { ...input };
  let modified = false;

  if (['Read', 'Write', 'Edit'].includes(toolName) && typeof input.file_path === 'string') {
    const rewritten = replaceInStr(input.file_path);
    if (rewritten !== input.file_path) { newInput.file_path = rewritten; modified = true; }
  }

  if (['Glob', 'Grep'].includes(toolName) && typeof input.path === 'string') {
    const rewritten = replaceInStr(input.path);
    if (rewritten !== input.path) { newInput.path = rewritten; modified = true; }
  }

  if (toolName === 'Bash' && typeof input.command === 'string') {
    const rewritten = replaceInStr(input.command);
    if (rewritten !== input.command) { newInput.command = rewritten; modified = true; }
  }

  return modified ? newInput : null;
}

/**
 * 评估工具调用是否安全
 * @param {string} toolName - 工具名称（如 Bash, Read, Write, Edit, Glob, Grep）
 * @param {Record<string, unknown>} input - 工具参数
 * @param {{ userUuid: string, cwd?: string }} opts
 * @returns {Promise<{ allowed: boolean, reason?: string, modifiedInput?: Record<string, unknown> }>}
 */
export async function evaluate(toolName, input, { userUuid, cwd }) {
  if (process.env.TOOL_GUARD_ENABLED === 'false') {
    return { allowed: true };
  }

  // 路径适配：将 .claude 相关路径重写为用户专属目录（多用户模式兼容）
  const { claudeDir } = getUserPaths(userUuid);
  const rewrittenInput = rewriteClaudePaths(toolName, input, claudeDir);
  const effectiveInput = rewrittenInput || input;

  if (VERBOSE) console.log(`[ToolGuard] INPUT ${toolName}:`, JSON.stringify(effectiveInput));

  if (rewrittenInput && VERBOSE) {
    console.log(`[ToolGuard] PATH-REWRITE ${toolName}: .claude paths → ${claudeDir}`);
  }

  const context = buildContext(userUuid, cwd);

  // Phase 1: 正则规则快速检查
  const { denied, uncertain, denyReasons, uncertainReasons } = evaluateRules(toolName, effectiveInput, context);

  if (denied) {
    if (VERBOSE) console.log(`[ToolGuard] RULE-DENY ${toolName}: ${denyReasons.join('; ')}`);
    return { allowed: false, reason: denyReasons.join('; ') };
  }

  if (!uncertain) {
    if (VERBOSE) console.log(`[ToolGuard] RULE-ALLOW ${toolName}`);
    return rewrittenInput ? { allowed: true, modifiedInput: rewrittenInput } : { allowed: true };
  }

  // Phase 2: LLM 兜底审查
  if (process.env.TOOL_GUARD_LLM_ENABLED === 'false') {
    if (VERBOSE) console.log(`[ToolGuard] LLM disabled, UNCERTAIN→ALLOW ${toolName}`);
    return rewrittenInput ? { allowed: true, modifiedInput: rewrittenInput } : { allowed: true };
  }

  try {
    const llmResult = await reviewWithLLM(toolName, effectiveInput, context, uncertainReasons);
    if (VERBOSE) console.log(`[ToolGuard] LLM-${llmResult.allowed ? 'ALLOW' : 'DENY'} ${toolName}: ${llmResult.reason || ''}`);
    return rewrittenInput && llmResult.allowed
      ? { ...llmResult, modifiedInput: rewrittenInput }
      : llmResult;
  } catch (err) {
    console.error(`[ToolGuard] LLM review error for ${toolName}:`, err.message);
    // LLM 失败时安全兜底：拒绝
    return { allowed: false, reason: 'LLM 审查失败，出于安全考虑已拒绝' };
  }
}

/**
 * 构建安全检查上下文
 */
function buildContext(userUuid, cwd) {
  const resolvedDataDir = path.resolve(DATA_DIR);
  return {
    userUuid,
    cwd: cwd ? path.resolve(cwd) : null,
    allowedPrefixes: [
      path.join(resolvedDataDir, 'user-data', userUuid),
      path.join(resolvedDataDir, 'user-projects', userUuid),
      path.join(resolvedDataDir, 'images', userUuid),
    ],
    dataDir: resolvedDataDir,
    tempDirs: ['/tmp', '/var/tmp', '/private/tmp'],
  };
}
