/**
 * ExecutionRouter -- per-agent 角色路由
 *
 * 职责：
 *   - 将 agent 的角色配置（chat/utility/embed 等）解析为执行所需的完整参数
 *   - 输入：role 名称 + agentConfig
 *   - 输出：{ modelId, providerId, api, apiKey, baseUrl }
 *   - 完全不参与模型注册逻辑（这是路由层，不是管理层）
 *
 * 角色路由配置存储格式（preferences.json / config.yaml）：
 *   models.chat           -> "provider/model" 或裸 modelId（向后兼容）
 *   models.utility        -> 同上
 *   models.utility_large  -> 同上
 *   models.embed          -> 同上
 *
 * 设计来源：Hana 自己的三通道 API 概念（两个参考项目都没有）
 */

import { t } from "../lib/i18n.ts";
import { isLocalBaseUrl } from "../shared/net-utils.ts";

// 角色名称 -> preferences 字段名（SHARED_MODEL_KEYS 兼容）
const ROLE_TO_PREF_KEY = {
  utility: "utility_model",
  utility_large: "utility_large_model",
};

function withCredentialMetadata(model: any, cred: any) {
  const headers = cred?.headers && typeof cred.headers === "object" ? cred.headers : {};
  const next = Object.keys(headers).length > 0
    ? { ...model, headers: { ...(model.headers || {}), ...headers } }
    : model;
  return cred?.accountId ? { ...next, accountId: cred.accountId } : next;
}

function hasCredentialHeaders(cred: any) {
  return !!cred?.headers && typeof cred.headers === "object" && Object.keys(cred.headers).length > 0;
}

export class ExecutionRouter {
  declare _resolveModel: (ref: string) => any;
  declare _providerRegistry: any;

  /**
   * @param {(ref: string) => object|null} resolveModel - 从 _availableModels 解析模型的函数
   * @param {import('./provider-registry.ts').ProviderRegistry} providerRegistry
   */
  constructor(resolveModel: any, providerRegistry: any) {
    this._resolveModel = resolveModel;
    this._providerRegistry = providerRegistry;
  }

  /**
   * 解析角色 -> 完整执行参数
   *
   * @param {string} roleOrRef
   *   角色名（"chat"/"utility"/"utility_large"/"embed"）
   *   或直接是模型引用（"provider/model" 或裸 modelId）
   * @param {object} agentConfig - agent config 对象（来自 config.yaml）
   * @param {object} [sharedModels] - 全局共享角色模型（来自 preferences）
   * @param {object} [utilApiOverride] - utility API 覆盖（来自 preferences）
   * @returns {{ modelId: string, providerId: string, api: string, apiKey: string, baseUrl: string }}
   * @throws 找不到模型或凭证时抛出
   */
  resolve(roleOrRef, agentConfig, sharedModels, utilApiOverride) {
    const modelRef = this._resolveRef(roleOrRef, agentConfig, sharedModels);
    if (!modelRef) {
      throw new Error(t("error.noUtilityModel") + ` (role: ${roleOrRef})`);
    }

    const model = this._resolveModel(modelRef);
    if (!model) {
      throw new Error(t("error.modelNotFound", { id: modelRef }));
    }

    // utility API 覆盖：只在 utility/utility_large 角色时生效
    const isUtilityRole = roleOrRef === "utility" || roleOrRef === "utility_large";
    if (isUtilityRole && utilApiOverride?.api_key) {
      // 校验 provider 一致性（与原 ModelManager.resolveUtilityConfig 行为一致）
      if (utilApiOverride.provider && utilApiOverride.provider !== model.provider) {
        throw new Error(t("error.utilityApiProviderMismatch", { model: modelRef }));
      }
      const overrideCred = this._providerRegistry.getCredentials(model.provider);
      return {
        modelId: model.id,
        providerId: model.provider,
        api: model.api,
        apiKey: utilApiOverride.api_key,
        baseUrl: utilApiOverride.base_url || model.baseUrl,
        headers: overrideCred?.headers || {},
      };
    }

    const cred = this._providerRegistry.getCredentials(model.provider);
    if (!cred) {
      throw new Error(t("error.providerMissingCreds", { provider: model.provider }));
    }
    if (!cred.api) {
      throw new Error(t("error.providerMissingApi", { provider: model.provider }));
    }
    if (!cred.baseUrl || (!cred.apiKey && !hasCredentialHeaders(cred) && !this._allowsMissingApiKey(model.provider, cred.baseUrl))) {
      throw new Error(t("error.providerMissingCreds", { provider: model.provider }));
    }

    return {
      modelId: model.id,
      providerId: model.provider,
      api: cred.api,
      apiKey: cred.apiKey,
      baseUrl: cred.baseUrl,
      headers: cred.headers || {},
      ...(cred.accountId ? { accountId: cred.accountId } : {}),
    };
  }

  /**
   * resolveUtilityConfig：解析 utility / utility_large 模型 + 凭证。
   *
   * 返回值的 utility / utility_large 字段是**完整 model 对象**（不再是裸 id 字符串）。
   * 所有 callText 调用方解构出 model 后直接传给 callText，由 callText 内部走 provider-compat。
   *
   * 显示用途（如 server banner）取 .id 字段：utilConfig.utility?.id。
   *
   * @param {object} agentConfig
   * @param {{ utility?: string|object, utility_large?: string|object }} sharedModels
   * @param {{ provider?: string, api_key?: string, base_url?: string }} utilApiOverride
   * @returns {{
   *   utility: object,
   *   utility_large: object,
   *   api_key: string, base_url: string, api: string,
   *   large_api_key: string, large_base_url: string, large_api: string,
   * }}
   */
  resolveUtilityConfig(agentConfig, sharedModels, utilApiOverride) {
    const cfg = agentConfig || {};
    const chatModelRef = cfg.models?.chat || null;

    // 用户明确配置的 utility 模型
    const userSetUtility = sharedModels?.utility || cfg.models?.utility || null;
    const userSetUtilityLarge = sharedModels?.utility_large || cfg.models?.utility_large || null;

    // 未配置时 fallback 到聊天模型
    const utilityModelRef = userSetUtility || chatModelRef;
    const largeModelRef = userSetUtilityLarge || chatModelRef;

    if (!utilityModelRef) throw new Error(t("error.noUtilityModel"));
    if (!largeModelRef) throw new Error(t("error.noUtilityLargeModel"));

    const utilModel = this._resolveModel(utilityModelRef);
    if (!utilModel) throw new Error(t("error.modelNotFound", { id: utilityModelRef }));

    const largeModel = this._resolveModel(largeModelRef);
    if (!largeModel) throw new Error(t("error.modelNotFound", { id: largeModelRef }));

    // utility 凭证
    let apiKey, baseUrl, api, utilCred;
    if (utilApiOverride?.provider || utilApiOverride?.api_key || utilApiOverride?.base_url) {
      // 校验 provider 一致性（与原 ModelManager.resolveUtilityConfig 行为一致）
      if (utilApiOverride.provider && utilApiOverride.provider !== utilModel.provider) {
        throw new Error(t("error.utilityApiProviderMismatch", { model: utilityModelRef }));
      }
      // utility API 覆盖（用户指定了独立的 utility api endpoint）
      utilCred = this._providerRegistry.getCredentials(utilModel.provider);
      api = utilCred?.api || utilModel.api;
      apiKey = utilApiOverride.api_key || "";
      baseUrl = utilApiOverride.base_url || "";
      if (!api) throw new Error(t("error.providerMissingApi", { provider: utilModel.provider }));
      if (!baseUrl || (!apiKey && !hasCredentialHeaders(utilCred) && !this._allowsMissingApiKey(utilModel.provider, baseUrl))) {
        throw new Error(t("error.utilityApiMissingCreds", { provider: utilModel.provider }));
      }
    } else {
      utilCred = this._providerRegistry.getCredentials(utilModel.provider);
      if (!utilCred?.api) throw new Error(t("error.providerMissingApi", { provider: utilModel.provider }));
      if (!utilCred.baseUrl || (!utilCred.apiKey && !hasCredentialHeaders(utilCred) && !this._allowsMissingApiKey(utilModel.provider, utilCred.baseUrl))) {
        throw new Error(t("error.providerMissingCreds", { provider: utilModel.provider }));
      }
      apiKey = utilCred.apiKey;
      baseUrl = utilCred.baseUrl;
      api = utilCred.api;
    }

    // utility_large 凭证（provider 相同则复用）
    let large_api_key = apiKey, large_base_url = baseUrl, large_api = api, largeCred = utilCred;
    if (largeModel.provider !== utilModel.provider) {
      largeCred = this._providerRegistry.getCredentials(largeModel.provider);
      if (!largeCred?.api) throw new Error(t("error.providerMissingApi", { provider: largeModel.provider }));
      if (!largeCred.baseUrl || (!largeCred.apiKey && !hasCredentialHeaders(largeCred) && !this._allowsMissingApiKey(largeModel.provider, largeCred.baseUrl))) {
        throw new Error(t("error.providerMissingCreds", { provider: largeModel.provider }));
      }
      large_api_key = largeCred.apiKey;
      large_base_url = largeCred.baseUrl;
      large_api = largeCred.api;
    }

    return {
      utility: withCredentialMetadata(utilModel, utilCred),
      utility_large: withCredentialMetadata(largeModel, largeCred),
      api_key: apiKey,
      base_url: baseUrl,
      api,
      large_api_key,
      large_base_url,
      large_api,
    };
  }

  /**
   * 将角色名或模型引用解析为实际模型 ref 字符串
   * @private
   */
  _resolveRef(roleOrRef, agentConfig, sharedModels) {
    const cfg = agentConfig || {};

    // 内置角色名的查找顺序：sharedModels -> agentConfig.models
    switch (roleOrRef) {
      case "chat":
        return cfg.models?.chat || null;
      case "utility":
        return sharedModels?.utility || cfg.models?.utility || null;
      case "utility_large":
        return sharedModels?.utility_large || cfg.models?.utility_large || null;
      case "embed":
        return cfg.embedding_api?.model || null;
      default:
        // 不是内置角色名，当作模型引用直接用
        return roleOrRef;
    }
  }

  _allowsMissingApiKey(provider, baseUrl) {
    return this._providerRegistry?.allowsMissingApiKey?.(provider, baseUrl)
      ?? isLocalBaseUrl(baseUrl);
  }
}
