/**
 * Builtin Tool Registry — 内置工具注册中心
 *
 * claude-agent-sdk 不提供添加自定义内置工具的 API，因此通过
 * "注入 system prompt + PreToolUse hook 拦截 Bash 命令"的方式模拟。
 *
 * 本模块采用 Registry + Strategy 模式：
 * - 每个工具是一个自包含的策略对象（name, systemPrompt, match, execute）
 * - Registry 统一管理注册、system prompt 合并、hook 分发、异步响应等待
 *
 * 扩展新工具只需在 tools/ 目录添加新模块并调用 registry.register()。
 */

import crypto from 'crypto';

// ─── 通用工具 ───

/**
 * 生成唯一请求 ID（用于 UI 审批/异步响应流）
 */
export function createRequestId() {
  if (typeof crypto.randomUUID === 'function') {
    return crypto.randomUUID();
  }
  return crypto.randomBytes(16).toString('hex');
}

// ─── Registry ───

class BuiltinToolRegistry {
  #tools = [];
  #responseTypes = new Set();
  #pendingRequests = new Map();
  /** tool_use_id → true，记录被内置工具拦截处理的工具调用（deny 即成功）*/
  #builtinHandledIds = new Set();

  /**
   * 注册一个内置工具
   * @param {{ name: string, responseType?: string, systemPrompt: string, match: Function, execute: Function }} tool
   */
  register(tool) {
    this.#tools.push(tool);
    if (tool.responseType) {
      this.#responseTypes.add(tool.responseType);
    }
  }

  /**
   * 合并所有工具的 systemPrompt 描述文本
   */
  getSystemPromptAppend() {
    return this.#tools.map(t => t.systemPrompt).join('\n');
  }

  /**
   * PreToolUse hook 入口：遍历工具匹配并执行
   * @param {object} hookInput - SDK PreToolUse hook 输入
   * @param {{ userUuid: string, cwd: string, mutableWriter: object }} ctx
   * @returns {object|null} SDK hook 返回值，无匹配时返回 null
   */
  async handlePreToolUse(hookInput, ctx) {
    for (const tool of this.#tools) {
      if (tool.match(hookInput)) {
        const toolContext = {
          ...ctx,
          createRequestId,
          waitForResponse: (requestId, timeoutMs) => this.#waitForResponse(requestId, timeoutMs),
        };

        try {
          const result = await tool.execute(hookInput, toolContext);

          // Bash 拦截型内置工具：execute() 副作用已完成，将 deny 转为 allow+printf
          // 让 AI 看到正常的 Bash 执行结果，避免因 is_error:true 误判为失败
          if (result.decision === 'deny' && hookInput.tool_name === 'Bash') {
            const msg = (result.reason || '')
              .replace(/\\/g, '\\\\')
              .replace(/'/g, "\\'")
              .replace(/\n/g, '\\n');
            return {
              hookSpecificOutput: {
                hookEventName: 'PreToolUse',
                permissionDecision: 'allow',
                updatedInput: { command: `printf '%s\n' $'${msg}'` },
              }
            };
          }

          // 非 Bash 工具（如 SDK CronCreate/CronDelete/CronList 重定向）保持 deny
          if (result.decision === 'deny' && hookInput.tool_use_id) {
            this.#builtinHandledIds.add(hookInput.tool_use_id);
          }
          return {
            hookSpecificOutput: {
              hookEventName: 'PreToolUse',
              permissionDecision: result.decision,
              ...(result.reason && { permissionDecisionReason: result.reason }),
              ...(result.updatedInput && { updatedInput: result.updatedInput }),
            }
          };
        } catch (err) {
          return {
            hookSpecificOutput: {
              hookEventName: 'PreToolUse',
              permissionDecision: 'deny',
              permissionDecisionReason: `内置工具 ${tool.name} 执行失败: ${err.message}`,
            }
          };
        }
      }
    }
    return null;
  }

  /**
   * 检查某个 tool_use_id 是否由内置工具拦截处理（deny = 成功）
   * 调用后自动从集合中移除（一次性消费）
   */
  consumeBuiltinHandled(toolUseId) {
    if (this.#builtinHandledIds.has(toolUseId)) {
      this.#builtinHandledIds.delete(toolUseId);
      return true;
    }
    return false;
  }

  /**
   * 检查 WS 消息类型是否属于内置工具的响应
   */
  canHandleResponse(type) {
    return this.#responseTypes.has(type);
  }

  /**
   * 解析异步等待中的 Promise（由 server/index.js WS 消息路由调用）
   */
  resolveResponse(requestId, data) {
    const resolver = this.#pendingRequests.get(requestId);
    if (resolver) resolver(data);
  }

  /**
   * 带超时的异步响应等待
   */
  #waitForResponse(requestId, timeoutMs) {
    return new Promise(resolve => {
      let settled = false;
      const finalize = (result) => {
        if (settled) return;
        settled = true;
        this.#pendingRequests.delete(requestId);
        clearTimeout(timeout);
        resolve(result);
      };
      const timeout = setTimeout(() => finalize(null), timeoutMs);
      this.#pendingRequests.set(requestId, finalize);
    });
  }
}

// ─── 单例创建 & 工具注册 ───

const registry = new BuiltinToolRegistry();

import shareProjectTemplate from './share-project-template.js';
registry.register(shareProjectTemplate);

import backgroundTask, { bgStatusTool } from './background-task.js';
registry.register(backgroundTask);
registry.register(bgStatusTool);

import { cronCreateTool, cronDeleteTool, cronListTool, sdkCronCreateRedirect, sdkCronDeleteRedirect, sdkCronListRedirect } from './cron-tool.js';
registry.register(cronCreateTool);
registry.register(cronDeleteTool);
registry.register(cronListTool);
// 拦截 SDK 原生 CronCreate/CronDelete/CronList，引导 AI 使用 Bash 版本
registry.register(sdkCronCreateRedirect);
registry.register(sdkCronDeleteRedirect);
registry.register(sdkCronListRedirect);

import userInfoTool from './user-info.js';
registry.register(userInfoTool);

// 重新导出后台任务相关模块，供 server/index.js 使用
export {
  backgroundTaskPool,
  enqueueResult,
  dequeueResult,
  hasResults,
  getAllPendingForUser,
} from './background-task-pool.js';

// 重新导出 cron 调度器，供 server/index.js 使用
export { cronScheduler } from './cron-scheduler.js';

export default registry;
