/**
 * ToolRegistry 工具注册表
 * 统一管理所有工具
 */

const { EventEmitter } = require('../utils/event-emitter');
const { globalCircuitBreaker } = require('../utils/circuit-breaker');
const { logger } = require('../utils/logger');
const { z } = require('zod');
const { withRetry, isNetworkError, PRESETS } = require('../utils/retry');
const { ErrorBoundary, Severity, RecoveryAction } = require('../utils/error-boundary');

const log = logger.child('ToolRegistry');

class ToolRegistry extends EventEmitter {
  constructor(options = {}) {
    super();
    this._tools = new Map();

    // 熔断器配置
    this._circuitBreakerEnabled = options.circuitBreaker !== false; // 默认启用
    this._circuitBreaker = globalCircuitBreaker;

    // 熔断器配置选项（可被工具覆盖）
    this._defaultCircuitBreakerOptions = {
      failureThreshold: options.failureThreshold || 3,
      successThreshold: options.successThreshold || 2,
      timeout: options.circuitBreakerTimeout || 60000,
    };
  }

  /**
   * 注册工具
   * @param {Object} tool - 工具定义
   * @param {string} tool.name - 工具名称
   * @param {string} tool.description - 工具描述
   * @param {Function} tool.execute - 执行函数
   * @param {Object} [tool.parameters] - 参数 schema
   * @param {Object} [tool.circuitBreaker] - 熔断器选项（覆盖默认值）
   * @param {Object} [tool.retry] - 重试配置（可使用 'fast', 'standard', 'conservative' 或自定义配置）
   */
  register(tool) {
    if (!tool.name) {
      throw new Error('Tool must have a name');
    }
    if (typeof tool.execute !== 'function') {
      throw new Error(`Tool '${tool.name}' must have an execute function`);
    }

    this._tools.set(tool.name, {
      name: tool.name,
      description: tool.description || '',
      inputSchema: tool.inputSchema || null,
      parameters: tool.parameters || null,
      execute: tool.execute,
      circuitBreakerOptions: tool.circuitBreaker || null,
      retryOptions: tool.retry || null, // 新的重试配置
    });

    this.emit('tool:registered', tool);
    return this;
  }

  /**
   * 批量注册工具
   * @param {Array<Object>} tools - 工具数组
   */
  registerMany(tools) {
    for (const tool of tools) {
      this.register(tool);
    }
    return this;
  }

  /**
   * 注销工具
   * @param {string} name - 工具名称
   */
  unregister(name) {
    const tool = this._tools.get(name);
    if (tool) {
      this._tools.delete(name);
      // 清理该工具的熔断器
      this._circuitBreaker.remove(name);
      this.emit('tool:unregistered', tool);
    }
    return this;
  }

  /**
   * 获取工具
   * @param {string} name - 工具名称
   * @returns {Object|undefined}
   */
  get(name) {
    return this._tools.get(name);
  }

  /**
   * 获取所有工具
   * @returns {Array<Object>}
   */
  getAll() {
    return Array.from(this._tools.values());
  }

  /**
   * 检查工具是否存在
   * @param {string} name - 工具名称
   * @returns {boolean}
   */
  has(name) {
    return this._tools.has(name);
  }

  /**
   * 获取工具熔断器状态
   * @param {string} name - 工具名称
   * @returns {Object|null}
   */
  getCircuitBreakerStatus(name) {
    if (!this._circuitBreakerEnabled) {
      return { enabled: false };
    }
    const breaker = this._circuitBreaker.get(name);
    return breaker ? breaker.getStatus() : null;
  }

  /**
   * 获取所有工具的熔断器状态
   * @returns {Object[]}
   */
  getAllCircuitBreakerStatus() {
    if (!this._circuitBreakerEnabled) {
      return [];
    }
    return this._circuitBreaker.getAllStatus();
  }

  /**
   * 重置工具的熔断器
   * @param {string} [name] - 工具名称，不传则重置所有
   */
  resetCircuitBreaker(name) {
    if (!this._circuitBreakerEnabled) {
      return;
    }
    if (name) {
      this._circuitBreaker.get(name)?.reset();
    } else {
      this._circuitBreaker.resetAll();
    }
  }

  /**
   * 执行工具（带熔断保护、参数验证、重试策略和错误边界）
   * @param {string} name - 工具名称
   * @param {Object} args - 参数
   * @param {Framework} framework - 框架实例
   * @returns {Promise<any>}
   */
  async execute(name, args, framework) {
    const tool = this._tools.get(name);
    if (!tool) {
      const error = new Error(`Tool '${name}' not found`);
      this.emit('tool:error', { name, args, error });
      throw error;
    }

    // ========== 参数验证 ==========
    let validatedArgs = args;
    if (tool.inputSchema) {
      try {
        // 如果 inputSchema 是 Zod schema，直接验证
        if (tool.inputSchema instanceof z.ZodType) {
          validatedArgs = tool.inputSchema.parse(args);
        }
        // 如果是普通对象（由 inputSchema.toJSON() 返回的格式），尝试构建 Zod schema
        else if (
          tool.inputSchema.type === 'object' ||
          (tool.inputSchema.jsonSchema && tool.inputSchema.jsonSchema.type === 'object')
        ) {
          const schemaDef = tool.inputSchema.jsonSchema || tool.inputSchema;
          const zodSchema = this._buildZodSchema(schemaDef);
          if (zodSchema) {
            validatedArgs = zodSchema.parse(args);
          }
        }
      } catch (err) {
        // 参数验证失败，返回详细的验证错误
        if (err instanceof z.ZodError) {
          const error = new Error(`Tool '${name}' 参数验证失败`);
          error.validationErrors = err.errors.map((e) => ({
            path: e.path.join('.'),
            message: e.message,
            expected: e.expected,
            received: e.received,
          }));
          error.toolName = name;
          error.toolArgs = args;
          error.errorType = 'VALIDATION_ERROR';
          this.emit('tool:error', { name, args, error });
          throw error;
        }
        // 其他错误（可能是非 Zod 错误），包装后抛出
        const error = new Error(`Tool '${name}' 参数解析失败: ${err.message}`);
        error.toolName = name;
        error.toolArgs = args;
        error.errorType = 'PARSE_ERROR';
        this.emit('tool:error', { name, args, error });
        throw error;
      }
    }

    // 获取该工具的熔断器选项和重试配置
    const cbOptions = {
      ...this._defaultCircuitBreakerOptions,
      ...(tool.circuitBreakerOptions || {}),
    };

    // 创建工具执行的错误边界
    const toolErrorBoundary = new ErrorBoundary({
      name: `tool:${name}`,
      logErrors: true,
      propagateErrors: false,
      onError: (error, context) => {
        // 判断错误类型，决定恢复策略
        if (isNetworkError(error)) {
          return RecoveryAction.RETRY;
        }
        if (error.circuitBreakerOpen) {
          return RecoveryAction.SKIP;
        }
        // 参数验证错误不重试
        if (error.errorType === 'VALIDATION_ERROR' || error.errorType === 'PARSE_ERROR') {
          return RecoveryAction.ABORT;
        }
        return RecoveryAction.RETRY;
      },
    });

    try {
      this.emit('tool:call', { name, args: validatedArgs });

      // 确定重试配置
      let retryConfig = tool.retryOptions;
      if (retryConfig) {
        // 如果是字符串，转换为预设配置
        if (typeof retryConfig === 'string') {
          retryConfig = PRESETS[retryConfig] || PRESETS.standard;
        }
        // 添加网络错误判断
        retryConfig.shouldRetry = retryConfig.shouldRetry || isNetworkError;
      }

      // 定义实际执行函数
      const executeTool = async () => {
        if (this._circuitBreakerEnabled) {
          // 使用熔断器执行
          return await this._circuitBreaker.execute(
            name,
            async () => {
              return await tool.execute(validatedArgs, framework);
            },
            cbOptions
          );
        } else {
          // 不使用熔断器，直接执行
          return await tool.execute(validatedArgs, framework);
        }
      };

      let result;
      if (retryConfig) {
        // 使用重试策略执行
        result = await withRetry(executeTool, {
          ...PRESETS.standard,
          ...retryConfig,
          onRetry: (error, attempt, delay) => {
            log.debug(
              `Tool '${name}' retry attempt ${attempt}: ${error.message} (delay: ${delay}ms)`
            );
            this.emit('tool:retry', { name, args: validatedArgs, error, attempt, delay });
          },
        });
      } else {
        // 不使用重试，直接执行
        result = await executeTool();
      }

      this.emit('tool:result', { name, args, result });
      return result;
    } catch (err) {
      // 包装错误信息，添加详细上下文
      const wrappedError = this._wrapToolError(err, name, validatedArgs);

      this.emit('tool:error', { name, args, error: wrappedError });
      throw wrappedError;
    }
  }

  /**
   * 包装工具错误，添加详细上下文信息
   * @private
   */
  _wrapToolError(err, toolName, args) {
    const wrappedError = new Error(`Tool '${toolName}' execution failed: ${err.message}`);

    // 保留原始错误引用
    wrappedError.originalError = err;
    wrappedError.toolName = toolName;
    wrappedError.toolArgs = args;

    // 错误分类
    if (isNetworkError(err)) {
      wrappedError.errorType = 'NETWORK_ERROR';
      wrappedError.recoverable = true;
    } else if (err.message && err.message.includes('Circuit breaker is OPEN')) {
      wrappedError.errorType = 'CIRCUIT_BREAKER_OPEN';
      wrappedError.circuitBreakerOpen = true;
      wrappedError.recoverable = false;
      log.warn(`Circuit breaker open for tool '${toolName}':`, err.message);
    } else if (err.name === 'ValidationError' || err.name === 'ZodError') {
      wrappedError.errorType = 'VALIDATION_ERROR';
      wrappedError.recoverable = false;
    } else if (err.name === 'TimeoutError') {
      wrappedError.errorType = 'TIMEOUT_ERROR';
      wrappedError.recoverable = true;
    } else {
      wrappedError.errorType = 'UNKNOWN_ERROR';
      wrappedError.recoverable = false;
    }

    // 错误发生时间
    wrappedError.timestamp = new Date().toISOString();

    // 堆栈跟踪（保留原始堆栈）
    wrappedError.stack = err.stack;

    return wrappedError;
  }

  /**
   * 清空所有工具
   */
  clear() {
    this._tools.clear();
    this._circuitBreaker.clear();
    this.emit('tool:cleared');
    return this;
  }

  /**
   * 获取工具数量
   * @returns {number}
   */
  size() {
    return this._tools.size;
  }

  /**
   * 将 JSON Schema 转换为 Zod Schema
   * @param {Object} schema - JSON Schema 对象
   * @returns {z.ZodObject|null} - 转换后的 Zod Schema，或 null 如果转换失败
   */
  _buildZodSchema(schema) {
    if (!schema || !schema.properties) {
      return null;
    }

    try {
      const shape = {};
      const properties = schema.properties || {};
      const required = schema.required || [];

      for (const [key, prop] of Object.entries(properties)) {
        shape[key] = this._jsonSchemaToZod(prop, key, required.includes(key));
      }

      const zodSchema = z.object(shape);

      // 如果没有必需字段，直接返回
      if (required.length === 0) {
        return zodSchema.optional();
      }

      // 返回带有必需字段约束的 schema
      return zodSchema;
    } catch (err) {
      log.warn('Failed to build Zod schema from JSON Schema:', err.message);
      return null;
    }
  }

  /**
   * 将单个 JSON Schema 属性转换为 Zod Type
   * @param {Object} prop - JSON Schema 属性定义
   * @param {string} name - 属性名称（用于错误消息）
   * @param {boolean} isRequired - 是否为必需字段
   * @returns {z.ZodType} - Zod 类型
   */
  _jsonSchemaToZod(prop, name, isRequired = false) {
    // 处理 $ref（不支持，返回 any）
    if (prop.$ref) {
      log.warn(`Property '${name}' has $ref, using z.any()`);
      return isRequired ? z.any() : z.any().optional();
    }

    // 处理 enum
    if (prop.enum) {
      let zodType = z.string().enum(prop.enum);
      if (prop.nullable) {
        zodType = zodType.nullable();
      }
      return isRequired ? zodType : zodType.optional();
    }

    // 根据 type 确定 Zod 类型
    const type = prop.type || 'string';

    let zodType;
    switch (type) {
      case 'string':
        zodType = z.string();
        if (prop.minLength !== undefined) {
          zodType = zodType.min(
            prop.minLength,
            prop.description || `Minimum length is ${prop.minLength}`
          );
        }
        if (prop.maxLength !== undefined) {
          zodType = zodType.max(
            prop.maxLength,
            prop.description || `Maximum length is ${prop.maxLength}`
          );
        }
        if (prop.pattern) {
          zodType = zodType.regex(
            new RegExp(prop.pattern),
            prop.description || `Pattern: ${prop.pattern}`
          );
        }
        break;

      case 'number':
      case 'integer':
        zodType = type === 'integer' ? z.number().int() : z.number();
        if (prop.minimum !== undefined) {
          zodType = zodType.min(prop.minimum);
        }
        if (prop.maximum !== undefined) {
          zodType = zodType.max(prop.maximum);
        }
        break;

      case 'boolean':
        zodType = z.boolean();
        break;

      case 'array':
        zodType = z.array(
          prop.items ? this._jsonSchemaToZod(prop.items, `${name}[]`, false) : z.any()
        );
        if (prop.minItems !== undefined) {
          zodType = zodType.min(prop.minItems);
        }
        if (prop.maxItems !== undefined) {
          zodType = zodType.max(prop.maxItems);
        }
        break;

      case 'object':
        if (prop.properties) {
          // 递归处理嵌套对象时，保持必需性信息
          const nestedRequired = prop.required || [];
          zodType = z.object(
            Object.fromEntries(
              Object.entries(prop.properties).map(([k, v]) => [
                k,
                this._jsonSchemaToZod(v, k, nestedRequired.includes(k)),
              ])
            )
          );
        } else {
          zodType = z.record(z.any());
        }
        break;

      case 'null':
        zodType = z.null();
        break;

      default:
        zodType = z.any();
    }

    // 处理 nullable
    if (prop.nullable === true || (Array.isArray(prop.type) && prop.type.includes('null'))) {
      zodType = zodType.nullable();
    }

    // 处理 default 值（作为可选的默认值）
    if (prop.default !== undefined) {
      zodType = zodType.optional().default(prop.default);
    }

    // 如果不是必需的，标记为可选
    // 注意：必需性由父级 object 的 required 数组决定
    if (!isRequired && prop.default === undefined) {
      zodType = zodType.optional();
    }

    return zodType;
  }
}

module.exports = { ToolRegistry };
