// exe-engine/src/router/age-router.js
// EXE-Engine · AGE-Router 路由网关
// 接收所有 AI 执行请求，进行鉴权、分类、路由
// PRJ-EXE-001 · Phase 0 · ZY-EXE-P0-001
// 版权：国作登字-2026-A-00037559

'use strict';

const { randomUUID } = require('crypto');

// HLI 501 存根路由（Phase 0 占位，后续 Phase 实现）
const { personaStubs } = require('./stubs/persona-stub');
const { userStubs } = require('./stubs/user-stub');
const { ticketStubs } = require('./stubs/ticket-stub');
const { dialogueStubs } = require('./stubs/dialogue-stub');
const { storageStubs } = require('./stubs/storage-stub');
const { dashboardStubs } = require('./stubs/dashboard-stub');

/**
 * AGE-Router 路由网关
 *
 * 本体论锚定：路由网关 = 笔的分流阀。
 * 所有墨水需求都从这里进入，网关决定用哪种墨水、多少量。
 *
 * 职责：
 *   1. 请求鉴权（验证用户身份 + 资源池额度）
 *   2. 任务分类（代码生成 / 文本处理 / 数据分析 / Agent 指令）
 *   3. 模型选择（通过 LoadBalancer 选择最优模型）
 *   4. 限流降级（资源池耗尽时的优雅降级策略）
 */
class AGERouter {
  /**
   * @param {object} deps
   * @param {LoadBalancer} deps.loadBalancer    负载均衡器
   * @param {ResourceMeter} deps.resourceMeter  资源计量器
   * @param {ContextCache} deps.contextCache    上下文缓存
   * @param {AgentController} deps.agentController Agent 调度器
   * @param {object} [deps.poolConfig]          资源池配置
   */
  constructor(deps) {
    this._loadBalancer = deps.loadBalancer;
    this._resourceMeter = deps.resourceMeter;
    this._contextCache = deps.contextCache;
    this._agentController = deps.agentController;
    this._poolConfig = deps.poolConfig || {};

    // 限流计数器 { agentId: { count, resetAt } }
    this._rateLimits = new Map();

    // HLI 存根路由注册表（天眼路由扫描识别用）
    this._hliStubs = [
      ...personaStubs,
      ...userStubs,
      ...ticketStubs,
      ...dialogueStubs,
      ...storageStubs,
      ...dashboardStubs
    ];
  }

  /**
   * 执行 AI 请求（统一入口）
   *
   * 对应 API: POST /api/exe/v1/execute
   *
   * @param {object} request
   * @param {string} request.agentId       Agent ID
   * @param {string} request.taskType      任务类型
   * @param {string} request.prompt        Prompt
   * @param {string} [request.systemPrompt] 系统 Prompt
   * @param {object} [request.context]     上下文
   * @param {object} [request.preferences] 偏好 { model, priority, maxTokens }
   * @param {string} [request.resourcePool] 资源池 ID
   * @param {string} [request.apiKey]      BYOK 模式的用户 Key
   * @returns {Promise<object>} EXE 标准响应
   */
  async execute(request) {
    const requestId = `exe-${randomUUID().slice(0, 12)}`;
    const startTime = Date.now();

    try {
      // 1. 限流检查
      this._checkRateLimit(request.agentId, request.resourcePool);

      // 2. 尝试加载缓存上下文
      const cacheKey = `${request.agentId}:${request.taskType}`;
      const cachedContext = this._contextCache.get(cacheKey);
      if (cachedContext && !request.context) {
        request.context = cachedContext;
      }

      // 3. 通过 LoadBalancer 选择适配器
      const adapter = this._loadBalancer.select({
        taskType: request.taskType,
        model: request.preferences?.model || 'auto',
        priority: request.preferences?.priority || 'balanced'
      });

      if (!adapter) {
        return this._buildErrorResponse(requestId, startTime, 'NO_AVAILABLE_MODEL',
          '没有可用的模型适配器，所有模型可能处于冷却期');
      }

      // 4. 执行推理
      const result = await adapter.execute({
        prompt: request.prompt,
        systemPrompt: request.systemPrompt,
        taskType: request.taskType,
        maxTokens: request.preferences?.maxTokens || 4096,
        temperature: request.preferences?.temperature
      });

      // 5. 记录计量数据
      const mode = request.apiKey ? 'byok' : 'pool';
      this._resourceMeter.record({
        requestId,
        agentId: request.agentId,
        model: result.model,
        taskType: request.taskType,
        resourcePool: request.resourcePool || 'default',
        mode,
        inputTokens: result.usage.inputTokens,
        outputTokens: result.usage.outputTokens,
        cost: result.usage.cost,
        costUnit: result.usage.unit,
        latency: result.latency,
        status: 'success'
      });

      // 6. 更新上下文缓存
      if (request.context) {
        this._contextCache.set(cacheKey, request.context);
      }

      // 7. 返回标准响应
      return {
        requestId,
        model: result.model,
        output: result.output,
        usage: result.usage,
        latency: result.latency,
        status: 'success'
      };

    } catch (err) {
      // 尝试故障转移
      const failoverResult = await this._tryFailover(request, requestId, startTime, err);
      if (failoverResult) return failoverResult;

      // 记录失败
      this._resourceMeter.record({
        requestId,
        agentId: request.agentId,
        model: 'unknown',
        taskType: request.taskType,
        resourcePool: request.resourcePool || 'default',
        mode: request.apiKey ? 'byok' : 'pool',
        inputTokens: 0,
        outputTokens: 0,
        cost: 0,
        costUnit: 'CNY',
        latency: Date.now() - startTime,
        status: 'error'
      });

      return this._buildErrorResponse(requestId, startTime, 'EXECUTION_FAILED', err.message);
    }
  }

  /**
   * 获取系统状态
   * @returns {object}
   */
  getStatus() {
    return {
      router: 'AGE-Router v1.0.0',
      project: 'PRJ-EXE-001',
      phase: 'Phase 0',
      adapters: this._loadBalancer.getStatus(),
      meter: this._resourceMeter.getSummary(),
      cache: this._contextCache.getStatus(),
      agents: this._agentController.getRegisteredAgents(),
      hliStubs: this._hliStubs.map(s => ({
        routeId: s.routeId,
        path: s.path,
        phase: s.phase,
        status: 'stub_501'
      }))
    };
  }

  /**
   * 处理 HLI 存根路由请求
   * @param {string} routePath  路由路径（如 /hli/persona/load）
   * @returns {object|null} 501 响应，不匹配返回 null
   */
  async handleStubRoute(routePath) {
    const stub = this._hliStubs.find(s => s.path === routePath);
    if (!stub) return null;
    return stub.handler({});
  }

  /**
   * 获取所有已注册的 HLI 存根路由
   * @returns {Array}
   */
  getHLIStubs() {
    return this._hliStubs;
  }

  // ── 内部方法 ──

  /**
   * 限流检查
   * @param {string} agentId
   * @param {string} poolId
   */
  _checkRateLimit(agentId, poolId) {
    const key = agentId || 'anonymous';
    const now = Date.now();
    let limiter = this._rateLimits.get(key);

    if (!limiter || now >= limiter.resetAt) {
      limiter = { count: 0, resetAt: now + 60000 }; // 每分钟窗口
      this._rateLimits.set(key, limiter);
    }

    limiter.count++;

    // 获取资源池的速率限制
    const pool = this._poolConfig.pools?.[poolId || 'default'];
    const limit = pool?.rateLimitPerMinute || 30;

    if (limiter.count > limit) {
      throw new Error(`[限流] Agent ${key} 每分钟请求数超限 (${limiter.count}/${limit})`);
    }
  }

  /**
   * 故障转移
   * @param {object} request
   * @param {string} requestId
   * @param {number} startTime
   * @param {Error} originalError
   * @returns {Promise<object|null>}
   */
  async _tryFailover(request, requestId, startTime, originalError) {
    try {
      const failoverAdapter = this._loadBalancer.failover(
        request.preferences?.model || 'unknown',
        request.taskType
      );

      if (!failoverAdapter) return null;

      const result = await failoverAdapter.execute({
        prompt: request.prompt,
        systemPrompt: request.systemPrompt,
        taskType: request.taskType,
        maxTokens: request.preferences?.maxTokens || 4096
      });

      this._resourceMeter.record({
        requestId,
        agentId: request.agentId,
        model: result.model,
        taskType: request.taskType,
        resourcePool: request.resourcePool || 'default',
        mode: request.apiKey ? 'byok' : 'pool',
        inputTokens: result.usage.inputTokens,
        outputTokens: result.usage.outputTokens,
        cost: result.usage.cost,
        costUnit: result.usage.unit,
        latency: result.latency,
        status: 'success'
      });

      return {
        requestId,
        model: result.model,
        output: result.output,
        usage: result.usage,
        latency: result.latency,
        status: 'success',
        _failover: true,
        _originalError: originalError.message
      };
    } catch (failoverErr) {
      // Failover also failed - return null to trigger error response
      this._lastFailoverError = failoverErr.message;
      return null;
    }
  }

  /**
   * 构建错误响应
   * @param {string} requestId
   * @param {number} startTime
   * @param {string} code
   * @param {string} message
   * @returns {object}
   */
  _buildErrorResponse(requestId, startTime, code, message) {
    return {
      requestId,
      model: null,
      output: null,
      usage: { inputTokens: 0, outputTokens: 0, cost: 0, unit: 'CNY' },
      latency: Date.now() - startTime,
      status: 'error',
      error: { code, message }
    };
  }
}

module.exports = AGERouter;
