// ═══════════════════════════════════════
// HLDP-ZY://agents/zhuyuan-dev-agent/modules/model-caller
// @guardian: ICE-GL-ZY001 · 铸渊
// @sovereign: TCS-0002∞ · 冰朔
// @copyright: 国作登字-2026-A-00037559
// ═══════════════════════════════════════
// 模型调用模块 v2.0 — 云雾API主用 + DeepSeek官方备份
// 主: https://api.yunwu.ai/v1 (OpenAI兼容)
// 备: https://api.deepseek.com/v1 (OpenAI兼容)
// 失败自动切换，不做数据丢失
// ═══════════════════════════════════════

const https = require("https");
const http = require("http");

// ═══ API 源配置 ═══
const API_SOURCES = [
  {
    name: "yunwu",
    base: process.env.YUNWU_BASE_URL || "https://api.yunwu.ai/v1",
    key: process.env.ZY_LLM_API_KEY || process.env.MODEL_API_KEY,
    model: process.env.YUNWU_MODEL || "deepseek-chat",
    timeout: 60000
  },
  {
    name: "deepseek",
    base: process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com/v1",
    key: process.env.DEEPSEEK_API_KEY || process.env.ZY_LLM_API_KEY,
    model: process.env.DEEPSEEK_MODEL || "deepseek-chat",
    timeout: 60000
  }
];

let currentSourceIndex = 0;
let sourceFailCounts = {};

/**
 * 调用大模型 — 主源失败自动切备份
 */
async function call(prompt, opts = {}) {
  const maxTries = API_SOURCES.length;
  let lastError = null;

  for (let attempt = 0; attempt < maxTries; attempt++) {
    const source = API_SOURCES[(currentSourceIndex + attempt) % API_SOURCES.length];

    if (!source.key) {
      console.warn("[ModelCaller] " + source.name + " 未配置key，跳过");
      continue;
    }

    try {
      console.log("[ModelCaller] 调用 " + source.name + " · 模型 " + source.model);
      const result = await callAPI(source, prompt, opts);
      console.log("[ModelCaller] " + source.name + " 返回 " + result.length + " 字符");

      // 成功 → 记录此源可用
      sourceFailCounts[source.name] = 0;
      return result;

    } catch (err) {
      console.warn("[ModelCaller] " + source.name + " 失败: " + err.message);
      sourceFailCounts[source.name] = (sourceFailCounts[source.name] || 0) + 1;
      lastError = err;

      // 切换到下一个源
      if (attempt < maxTries - 1) {
        console.log("[ModelCaller] 切换备用源...");
      }
    }
  }

  throw new Error("所有API源均失败。最后错误: " + (lastError ? lastError.message : "未知"));
}

/**
 * 调用单个 API 源
 */
function callAPI(source, prompt, opts) {
  const body = JSON.stringify({
    model: source.model,
    messages: [
      { role: "system", content: "你是一个技术开发Agent。回答要精确、结构化、可执行。使用中文。" },
      { role: "user", content: prompt }
    ],
    max_tokens: opts.max_tokens || 4096,
    temperature: opts.temperature || 0.3
  });

  return new Promise((resolve, reject) => {
    const url = new URL(source.base + "/chat/completions");
    const lib = url.protocol === "https:" ? https : http;

    const req = lib.request({
      hostname: url.hostname,
      port: url.port || (url.protocol === "https:" ? 443 : 80),
      path: url.pathname + url.search,
      method: "POST",
      timeout: source.timeout,
      headers: {
        "Authorization": "Bearer " + source.key,
        "Content-Type": "application/json",
        "Content-Length": Buffer.byteLength(body)
      }
    }, (res) => {
      let data = "";
      res.on("data", (c) => data += c);
      res.on("end", () => {
        try {
          const json = JSON.parse(data);
          if (json.error) {
            reject(new Error(source.name + " API错误: " + (json.error.message || JSON.stringify(json.error))));
            return;
          }
          const content = json.choices?.[0]?.message?.content || "";
          if (!content) {
            reject(new Error(source.name + " 空回复"));
            return;
          }
          resolve(content);
        } catch (e) {
          reject(new Error(source.name + " 解析失败: " + data.slice(0, 200)));
        }
      });
    });

    req.on("timeout", () => {
      req.destroy();
      reject(new Error(source.name + " 请求超时 " + source.timeout + "ms"));
    });

    req.on("error", (e) => reject(new Error(source.name + " 网络错误: " + e.message)));
    req.write(body);
    req.end();
  });
}

/**
 * 获取当前状态
 */
function getStatus() {
  return {
    primary: API_SOURCES[0].name,
    backup: API_SOURCES[1] ? API_SOURCES[1].name : "none",
    failCounts: sourceFailCounts,
    currentIndex: currentSourceIndex
  };
}

module.exports = { call, getStatus };
