/*!
 * @name 全豆要[聚合音源] v11智谱版
 * @description 基于v5.1全面升级，聚合星海/溯音/念心/长青/野花/汽水VIP等多源音源
 *              智能健康调度 | 严格防错歌 | 全局开关 | 缓存优化 | 最强兜底
 * @version v11.0
 * @author 全豆要 → v11智谱版升级 | 野花音源集成
 */

// ===================== 工具函数 =====================
function noop() {}

// ===================== 全局配置（可按需调整） =====================
const GLOBAL_CONFIG = {
  enabled: true,                      // 全局总开关
  healthCheckEnabled: true,           // 智能健康调度开关
  antiWrongSongEnabled: true,         // 严格防错歌开关
  cacheEnabled: true,                 // 缓存开关
  healthScoreThreshold: 30,           // 健康分低于此值降权（0-100）
  healthRecoveryPerSuccess: 10,       // 每次成功恢复分数
  healthPenaltyPerFailure: 20,        // 每次失败扣除分数
  requestTimeout: 8000,               // 默认请求超时 ms
  cacheMaxSize: 800,                  // 缓存最大条目
  cacheDefaultTTL: 21600000,          // 缓存默认过期 6小时
  concurrentSources: 3,               // 并发请求源数量
};

// ===================== 各源独立开关 =====================
const SOURCE_SWITCHES = {
  xinghai:        true,   // 星海主
  xinghaiBackup:  true,   // 星海备
  suyinQQ:        true,   // 溯音QQ
  suyin163:       true,   // 溯音163
  suyinKuwo:      true,   // 溯音酷我
  suyinMigu:      true,   // 溯音咪咕
  changqingVip:   true,   // 长青SVIP
  nianxinVip:     true,   // 念心SVIP
  yehua:          true,   // 野花音源（备用）
  qishui:         true,   // 汽水VIP
};

// ===================== API 端点 =====================
const XINGHAI_MAIN_API = "https://music-api.gdstudio.xyz/api.php?use_xbridge3=true&loader_name=forest&need_sec_link=1&sec_link_scene=im&theme=light";
const XINGHAI_BACKUP_API = "https://music-dl.sayqz.com/api/";

const SUYIN_QQ_API = "https://oiapi.net/api/QQ_Music";
const SUYIN_QQ_KEY = "oiapi-ef6133b7-ac2f-dc7d-878c-d3e207a82575";
const SUYIN_163_API = "https://oiapi.net/api/Music_163";
const SUYIN_KUWO_API = "https://oiapi.net/api/Kuwo";
const SUYIN_MIGU_API = "https://api.xcvts.cn/api/music/migu";

const CHANGQING_URL_TEMPLATES = {
  tx: "http://175.27.166.236/kgqq/qq.php?type=mp3&id={id}&level={level}",
  wy: "http://175.27.166.236/wy/wy.php?type=mp3&id={id}&level={level}",
  kw: "https://musicapi.haitangw.net/music/kw.php?type=mp3&id={id}&level={level}",
  kg: "https://music.haitangw.cc/kgqq/kg.php?type=mp3&id={id}&level={level}",
  mg: "https://music.haitangw.cc/musicapi/mg.php?type=mp3&id={id}&level={level}",
};

const NIANXIN_URL_TEMPLATES = {
  tx: "https://music.nxinxz.com/kgqq/tx.php?id={id}&level={level}&type=mp3",
  wy: "http://music.nxinxz.com/wy.php?id={id}&level={level}&type=mp3",
  kw: "http://music.nxinxz.com/kw.php?id={id}&level={level}&type=mp3",
  kg: "https://music.nxinxz.com/kgqq/kg.php?id={id}&level={level}&type=mp3",
  mg: "http://music.nxinxz.com/mg.php?id={id}&level={level}&type=mp3",
};

// 野花音源 API（从混淆代码逆向解析）
const YEHUA_BASE_URL = "http://97.64.37.235/lx-music/";

// 汽水VIP
const QISHUI_SOURCE_ID = "qsvip";
const QISHUI_SOURCE_NAME = "汽水VIP";
const QISHUI_API_HTTPS = "https://api.vsaa.cn/api/music.qishui.vip";
const QISHUI_API_HTTP = "http://api.vsaa.cn/api/music.qishui.vip";
const QISHUI_PROXY_API = "https://proxy.qishui.vsaa.cn/qishui/proxy";

// ===================== 平台与音质映射 =====================
const PLATFORM_QUALITIES = {
  wy: ["24bit", "flac", "320k", "192k", "128k"],
  tx: ["24bit", "flac", "320k", "192k", "128k"],
  kw: ["24bit", "flac", "320k", "192k", "128k"],
  kg: ["24bit", "flac", "320k", "192k", "128k"],
  mg: ["24bit", "flac", "320k", "192k", "128k"],
};

const PLATFORM_NAMES = {
  wy: "网易云音乐",
  tx: "QQ音乐",
  kw: "酷我音乐",
  kg: "酷狗音乐",
  mg: "咪咕音乐",
};

const PLATFORM_TO_XINGHAI = {
  wy: "netease", tx: "tencent", kw: "kuwo", kg: "kugou", mg: "migu"
};

const PLATFORM_TO_XINGHAI_BACKUP = {
  wy: "netease", tx: "qq", kw: "kuwo"
};

const QUALITY_TO_BR = {
  "128k": "128", "192k": "192", "320k": "320",
  flac: "740", flac24bit: "999", "24bit": "999"
};

const QUALITY_TO_SUYIN_QQ_BR = {
  "128k": 7, "320k": 5, flac: 4, hires: 3, atmos: 2, master: 1, "24bit": 1
};

const QUALITY_TO_KUWO_BR = {
  flac: 1, "320k": 5, "128k": 7, "24bit": 1
};

const HIRES_QUALITY_SET = new Set(["24bit", "flac", "flac24bit", "hires", "master", "atmos"]);

const HTTP_URL_REGEX = /^https?:\/\//i;

// ===================== LX Music API =====================
const {
  EVENT_NAMES,
  request,
  on,
  send
} = globalThis.lx;

// ===================== LRU 缓存管理器（优化版） =====================
class LRUCache {
  constructor(maxSize, defaultTTL) {
    this.cache = new Map();
    this.maxSize = maxSize || GLOBAL_CONFIG.cacheMaxSize;
    this.defaultTTL = defaultTTL || GLOBAL_CONFIG.cacheDefaultTTL;
    this.hits = 0;
    this.misses = 0;
  }

  get(key) {
    if (!GLOBAL_CONFIG.cacheEnabled) return null;
    const entry = this.cache.get(key);
    if (!entry) { this.misses++; return null; }
    if (Date.now() - entry.timestamp >= entry.ttl) {
      this.cache.delete(key);
      this.misses++;
      return null;
    }
    // LRU: 移到末尾（最近使用）
    this.cache.delete(key);
    this.cache.set(key, entry);
    this.hits++;
    return entry.value;
  }

  set(key, value, ttl) {
    if (!GLOBAL_CONFIG.cacheEnabled) return;
    if (this.cache.has(key)) this.cache.delete(key);
    // 淘汰最旧条目
    while (this.cache.size >= this.maxSize) {
      const oldest = this.cache.keys().next().value;
      if (oldest !== undefined) this.cache.delete(oldest);
      else break;
    }
    this.cache.set(key, {
      value,
      timestamp: Date.now(),
      ttl: ttl || this.defaultTTL
    });
  }

  has(key) {
    if (!GLOBAL_CONFIG.cacheEnabled) return false;
    const entry = this.cache.get(key);
    if (!entry) return false;
    if (Date.now() - entry.timestamp >= entry.ttl) {
      this.cache.delete(key);
      return false;
    }
    return true;
  }

  delete(key) { this.cache.delete(key); }

  clear() { this.cache.clear(); this.hits = 0; this.misses = 0; }

  get size() { return this.cache.size; }

  getStats() {
    const total = this.hits + this.misses;
    return {
      size: this.cache.size,
      maxSize: this.maxSize,
      hits: this.hits,
      misses: this.misses,
      hitRate: total > 0 ? (this.hits / total * 100).toFixed(1) + "%" : "N/A"
    };
  }
}

const urlCache = new LRUCache(GLOBAL_CONFIG.cacheMaxSize, GLOBAL_CONFIG.cacheDefaultTTL);

// ===================== 智能健康调度系统 =====================
const healthStats = {};

function initHealth(name) {
  if (!healthStats[name]) {
    healthStats[name] = {
      success: 0,
      failure: 0,
      lastSuccess: 0,
      lastFailure: 0,
      score: 100,           // 初始满分
      consecutiveFailures: 0
    };
  }
}

function recordSuccess(name) {
  if (!GLOBAL_CONFIG.healthCheckEnabled) return;
  initHealth(name);
  const s = healthStats[name];
  s.success++;
  s.lastSuccess = Date.now();
  s.consecutiveFailures = 0;
  s.score = Math.min(100, s.score + GLOBAL_CONFIG.healthRecoveryPerSuccess);
}

function recordFailure(name) {
  if (!GLOBAL_CONFIG.healthCheckEnabled) return;
  initHealth(name);
  const s = healthStats[name];
  s.failure++;
  s.lastFailure = Date.now();
  s.consecutiveFailures++;
  // 连续失败加重惩罚，防止反复尝试已挂的源
  const penalty = GLOBAL_CONFIG.healthPenaltyPerFailure + Math.min(s.consecutiveFailures * 5, 30);
  s.score = Math.max(0, s.score - penalty);
}

function getHealthScore(name) {
  initHealth(name);
  return healthStats[name].score;
}

function isSourceHealthy(name) {
  if (!GLOBAL_CONFIG.healthCheckEnabled) return true;
  if (SOURCE_SWITCHES[name] === false) return false;
  return getHealthScore(name) >= GLOBAL_CONFIG.healthScoreThreshold;
}

// ===================== 严格防错歌系统 =====================
function normalizeKeyword(keyword) {
  if (!keyword) return "";
  return String(keyword)
    .replace(/\(\s*Live\s*\)/gi, "")
    .replace(/\([^)]*\)/g, "")
    .replace(/\s+/g, "")
    .replace(/[^\w\u4e00-\u9fa5]/g, "")
    .trim()
    .toLowerCase();
}

function titleFuzzyMatch(a, b) {
  const na = normalizeKeyword(a);
  const nb = normalizeKeyword(b);
  if (!na || !nb) return true;
  return na.includes(nb) || nb.includes(na);
}

// 对搜索结果进行严格匹配验证（防错歌核心）
function verifySearchResult(resultData, songInfo) {
  if (!GLOBAL_CONFIG.antiWrongSongEnabled) return true;
  if (!songInfo?.name) return true;

  const resultName = resultData?.song || resultData?.name || resultData?.title || "";
  const resultSinger = resultData?.singer || resultData?.artist || "";
  const resultAlbum = resultData?.album || resultData?.albumName || "";

  // 歌名必须匹配
  if (!titleFuzzyMatch(resultName, songInfo.name)) return false;

  // 歌手必须匹配（双方都有信息时）
  if (songInfo.singer && resultSinger) {
    if (!titleFuzzyMatch(resultSinger, songInfo.singer)) return false;
  }

  // 专辑匹配（双方都有信息时）
  if ((songInfo.albumName || songInfo.album) && resultAlbum) {
    if (!titleFuzzyMatch(resultAlbum, songInfo.albumName || songInfo.album)) return false;
  }

  return true;
}

// 从文本消息解析歌曲信息
function parseMessageSongInfo(message) {
  if (!message) return null;
  const result = {};
  for (const line of String(message).split("\n")) {
    if (line.startsWith("歌名：")) result.song = line.replace("歌名：", "").trim();
    if (line.startsWith("歌手：")) result.singer = line.replace("歌手：", "").trim();
    if (line.startsWith("专辑：")) result.album = line.replace("专辑：", "").trim();
  }
  return result.song ? result : null;
}

// ===================== HTTP 请求工具 =====================
function httpRequest(url, options = {}) {
  return new Promise((resolve, reject) => {
    request(url, {
      timeout: GLOBAL_CONFIG.requestTimeout,
      ...options
    }, (err, res) => {
      if (err) return reject(new Error("请求错误: " + err.message));
      let body = res?.body;
      if (typeof body === "string") {
        const trimmed = body.trim();
        if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith('"')) {
          try { body = JSON.parse(trimmed); } catch (e) { /* 保持原字符串 */ }
        }
      }
      resolve({
        statusCode: res?.statusCode ?? 0,
        headers: res?.headers || {},
        body
      });
    });
  });
}

async function httpGet(url, params = {}) {
  const queryStr = Object.keys(params)
    .filter(k => params[k] !== undefined && params[k] !== null)
    .map(k => encodeURIComponent(k) + "=" + encodeURIComponent(params[k]))
    .join("&");
  const sep = url.includes("?") ? "&" : "?";
  const fullUrl = url + (queryStr ? sep + queryStr : "");
  const res = await httpRequest(fullUrl, { method: "GET" });
  if (res.statusCode >= 400) throw new Error("HTTP " + res.statusCode);
  return res.body;
}

function buildQueryString(params = {}) {
  const parts = Object.keys(params)
    .filter(k => params[k] !== undefined && params[k] !== null)
    .map(k => encodeURIComponent(String(k)) + "=" + encodeURIComponent(String(params[k])));
  return parts.length ? "?" + parts.join("&") : "";
}

async function httpGetWithFallback(url, params = {}, timeout) {
  const urls = url === QISHUI_API_HTTPS ? [QISHUI_API_HTTPS, QISHUI_API_HTTP] : [url];
  let lastError = null;
  for (const u of urls) {
    try {
      const fullUrl = u + buildQueryString(params);
      const res = await httpRequest(fullUrl, { method: "GET", timeout: timeout || GLOBAL_CONFIG.requestTimeout });
      if (res.statusCode >= 400) throw new Error("HTTP " + res.statusCode);
      return res.body;
    } catch (e) { lastError = e; }
  }
  throw lastError || new Error("请求失败");
}

async function httpPost(url, body = {}, timeout) {
  const res = await httpRequest(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body,
    timeout: timeout || GLOBAL_CONFIG.requestTimeout
  });
  if (res.statusCode >= 400) throw new Error("HTTP " + res.statusCode);
  return res.body;
}

// ===================== 歌曲信息工具 =====================
function getSongId(songInfo) {
  return (songInfo?.id || songInfo?.songmid || songInfo?.songId ||
    songInfo?.hash || songInfo?.rid || songInfo?.mid ||
    songInfo?.strMediaMid || songInfo?.mediaId || "").toString();
}

function getHashOrMid(songInfo) {
  return songInfo?.hash ?? songInfo?.songmid ?? songInfo?.id ?? null;
}

function getQQSongId(songInfo) {
  const mid = songInfo?.meta?.qq?.mid || songInfo?.meta?.mid || songInfo?.songmid ||
    (typeof songInfo?.id === "string" && !/^\d+$/.test(songInfo.id) ? songInfo.id : null);
  if (mid) return { type: "mid", value: mid };
  const songid = songInfo?.meta?.qq?.songid || songInfo?.meta?.songid ||
    (typeof songInfo?.id === "number" ? songInfo.id :
      (typeof songInfo?.id === "string" && /^\d+$/.test(songInfo.id) ? Number(songInfo.id) : null));
  if (songid) return { type: "songid", value: songid };
  return null;
}

function getPlatformSongId(platform, songInfo) {
  if (platform === "kg") {
    return songInfo?.hash || songInfo?.songmid || songInfo?.id || songInfo?.rid || songInfo?.mid || null;
  }
  if (platform === "tx") {
    const qqId = getQQSongId(songInfo);
    if (qqId?.value) return qqId.value;
  }
  return songInfo?.songmid || songInfo?.id || songInfo?.songId || songInfo?.rid || songInfo?.hash || null;
}

function normalizeQuality(quality) {
  switch (String(quality || "").toLowerCase()) {
    case "128k": return "low";
    case "320k": return "standard";
    case "flac": return "lossless";
    case "flac24bit": return "flac24bit";
    default: return "128k";
  }
}

function qualityToNetease(quality) {
  const q = String(quality || "128k").toLowerCase();
  if (["flac", "flac24bit", "hires", "master", "atmos"].includes(q)) return "lossless";
  if (["320k", "192k"].includes(q)) return "exhigh";
  return "standard";
}

function selectQuality(requested, supported) {
  if (requested === "24bit" && Array.isArray(supported) && supported.includes("24bit")) return "24bit";
  const list = Array.isArray(supported) ? supported : ["128k"];
  const normalized = String(requested || "128k").toLowerCase();
  if (list.includes(normalized)) return normalized;
  const order = ["flac24bit", "flac", "320k", "192k", "128k"];
  let idx = order.indexOf(normalized);
  if (idx < 0) idx = order.length - 1;
  for (let i = idx; i < order.length; i++) {
    if (list.includes(order[i])) return order[i];
  }
  for (let i = order.length - 1; i >= 0; i--) {
    if (list.includes(order[i])) return order[i];
  }
  return list[0] || "128k";
}

function qualityToSuyinQQ(quality) {
  const q = String(quality || "128k").toLowerCase();
  if (q === "flac24bit") return "hires";
  if (q === "192k") return "320k";
  return QUALITY_TO_SUYIN_QQ_BR.hasOwnProperty(q) ? q : "128k";
}

function validateUrl(url, sourceName) {
  if (!url || typeof url !== "string") throw new Error(sourceName + "返回空URL");
  if (!HTTP_URL_REGEX.test(url.trim())) throw new Error(sourceName + "非法URL格式");
  return url;
}

function buildCacheKey(prefix, songInfo, quality) {
  return prefix + "_" + (songInfo?.name || "") + "_" + (songInfo?.singer || "") + "_" + (songInfo?.albumName || songInfo?.album || "") + "_" + (quality || "");
}

function buildSearchKeywords(songInfo) {
  const keywords = [];
  const name = songInfo?.name || "";
  const album = songInfo?.albumName || songInfo?.album || "";
  const singer = songInfo?.singer || "";
  if (name && album) {
    const kw = normalizeKeyword(name + album);
    if (kw) keywords.push({ keyword: kw, strict: true });
  }
  if (name && singer) {
    const kw = normalizeKeyword(name + singer);
    if (kw) keywords.push({ keyword: kw, strict: true });
  }
  if (name) {
    const kw = normalizeKeyword(name);
    if (kw) keywords.push({ keyword: kw, strict: false });
  }
  return keywords;
}

function getFirstData(response) {
  const data = response?.data;
  if (Array.isArray(data)) return data[0] || null;
  if (data && typeof data === "object" && data[0]) return data[0];
  return null;
}

function buildTemplateUrl(platform, quality, songInfo, templates, sourceName) {
  const template = templates[platform];
  if (!template) throw new Error(sourceName + "不支持该平台");
  const songId = getPlatformSongId(platform, songInfo);
  if (!songId) throw new Error(sourceName + "缺少songId");
  const level = qualityToNetease(quality);
  return template
    .replace("{id}", encodeURIComponent(String(songId)))
    .replace("{level}", encodeURIComponent(level));
}

function getMobileUserAgent() {
  return "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1";
}

function normalizeSongInfo(raw) {
  const id = raw?.id || raw?.vid ? String(raw.id || raw.vid) : "";
  return {
    id,
    songmid: id,
    hash: id,
    name: raw?.name ? String(raw.name) : "未知歌曲",
    singer: raw?.artists ? String(raw.artists) : "未知歌手",
    albumName: raw?.album ? String(raw.album) : "",
    duration: raw?.duration ? Math.floor(Number(raw.duration) / 1000) : 0,
    pic: raw?.cover || raw?.pic ? String(raw.cover || raw.pic) : "",
    _raw: raw || {}
  };
}

// ===================== 各音源获取URL实现 =====================

// --- 星海主API ---
async function xinghaiMainGetUrl(platform, songId, quality, songInfo) {
  const source = PLATFORM_TO_XINGHAI[platform];
  if (!source) throw new Error("星海主API不支持该平台");
  const id = songId ?? getHashOrMid(songInfo);
  if (!id) throw new Error("星海主缺少songId");
  const selectedQuality = selectQuality(quality, ["128k", "192k", "320k", "flac", "flac24bit"]);
  const br = QUALITY_TO_BR[selectedQuality];
  if (!br) throw new Error("星海主API音质映射失败");
  const url = XINGHAI_MAIN_API + "&types=url&source=" + source + "&id=" + encodeURIComponent(id) + "&br=" + br;
  const res = await httpRequest(url, {
    method: "GET",
    headers: { "User-Agent": "LX-Music-Mobile", Accept: "application/json" }
  });
  const body = res.body;
  if (!body || typeof body !== "object" || !body.url) {
    throw new Error(body?.message || "星海主API未返回可用URL");
  }
  return body.url;
}

// --- 星海备API ---
async function xinghaiBackupGetUrl(platform, songId, quality, songInfo) {
  const source = PLATFORM_TO_XINGHAI_BACKUP[platform];
  if (!source) throw new Error("星海备API不支持该平台");
  const id = songId ?? getHashOrMid(songInfo);
  if (!id) throw new Error("星海备缺少songId");
  const selectedQuality = selectQuality(quality, ["128k", "192k", "320k", "flac", "flac24bit"]);
  return XINGHAI_BACKUP_API + "?source=" + encodeURIComponent(source) + "&id=" + encodeURIComponent(id) + "&type=url&br=" + encodeURIComponent(selectedQuality);
}

// --- 溯音QQ ---
function extractQQUrl(responseData) {
  if (responseData?.music) return responseData.music;
  if (responseData?.url) return responseData.url;
  if (responseData?.message) {
    const match = String(responseData.message).match(/音频链接[：:](.+?)(?:\n|$)/);
    if (match && match[1]) return match[1].trim();
  }
  throw new Error("溯音QQ未找到音频链接");
}

async function suyinQQGetUrl(songInfo, quality) {
  const qqId = getQQSongId(songInfo);
  if (!qqId) throw new Error("溯音QQ缺少songmid/id");
  const normalizedQuality = qualityToSuyinQQ(quality);
  const startBr = QUALITY_TO_SUYIN_QQ_BR[normalizedQuality] || QUALITY_TO_SUYIN_QQ_BR["128k"];
  const brList = [startBr, 4, 5, 7]
    .filter(function(val, idx, arr) { return arr.indexOf(val) === idx && val >= startBr; })
    .sort(function(a, b) { return a - b; });
  let lastError = null;
  for (const br of brList) {
    try {
      const reqParams = { key: SUYIN_QQ_KEY, type: "json", br: br, n: 1 };
      if (qqId.type === "mid") reqParams.mid = qqId.value;
      else reqParams.songid = qqId.value;
      const res = await httpGet(SUYIN_QQ_API, reqParams);
      return extractQQUrl(res);
    } catch (e) { lastError = e; }
  }
  throw new Error("溯音QQ全部音质尝试失败: " + (lastError?.message || "unknown"));
}

// --- 溯音163 ---
async function suyin163GetUrl(songInfo) {
  const id = songInfo?.songmid || songInfo?.id;
  if (!id) throw new Error("溯音163缺少songmid/id");
  const res = await httpGet(SUYIN_163_API, { id: id });
  if (res?.code === 0 && res?.data) {
    const item = Array.isArray(res.data) ? res.data[0] : res.data;
    if (item?.url) return item.url;
  }
  throw new Error("溯音163获取失败");
}

// --- 溯音酷我 ---
async function suyinKuwoSearch(keyword, br, songInfo) {
  const res = await httpGet(SUYIN_KUWO_API, { msg: keyword, n: 1, br: br });
  if (res?.data?.url) {
    if (songInfo && !verifySearchResult(res, songInfo)) {
      throw new Error("溯音酷我歌曲信息不匹配（防错歌拦截）");
    }
    return res.data.url;
  }
  if (res?.message) {
    const match = String(res.message).match(/音乐链接[：:](\S+)/);
    if (match && match[1]) {
      if (songInfo) {
        const parsed = parseMessageSongInfo(res.message);
        if (parsed && !verifySearchResult(parsed, songInfo)) {
          throw new Error("溯音酷我歌曲信息不匹配（防错歌拦截）");
        }
      }
      return match[1];
    }
  }
  throw new Error("溯音酷我未找到链接");
}

async function suyinKuwoGetUrl(songInfo, quality) {
  if (!songInfo?.name) throw new Error("溯音酷我需要歌曲名");
  const cacheKey = buildCacheKey("kw", songInfo, quality);
  const cached = urlCache.get(cacheKey);
  if (cached) return cached;
  const selectedQuality = selectQuality(quality, ["flac", "320k", "128k"]);
  const br = QUALITY_TO_KUWO_BR[selectedQuality] || 1;
  const keywords = buildSearchKeywords(songInfo);
  let lastError = null;
  for (const item of keywords) {
    try {
      const url = await suyinKuwoSearch(item.keyword, br, item.strict ? songInfo : null);
      if (url) {
        urlCache.set(cacheKey, url);
        return url;
      }
    } catch (e) { lastError = e; }
  }
  throw new Error("溯音酷我失败: " + (lastError?.message || "unknown"));
}

// --- 溯音咪咕 ---
async function suyinMiguGetUrl(songInfo) {
  if (!songInfo?.name) throw new Error("溯音咪咕需要歌曲名");
  const cacheKey = buildCacheKey("mg", songInfo);
  const cached = urlCache.get(cacheKey);
  if (cached) return cached;
  const keywords = buildSearchKeywords(songInfo);
  let lastError = null;
  for (const item of keywords) {
    try {
      const res = await httpGet(SUYIN_MIGU_API, { gm: item.keyword, n: 1, num: 1, type: "json" });
      if (res?.code === 200 && res?.musicInfo) {
        if (item.strict && !verifySearchResult(res, songInfo)) {
          throw new Error("溯音咪咕歌曲信息不匹配（防错歌拦截）");
        }
        urlCache.set(cacheKey, res.musicInfo);
        return res.musicInfo;
      }
    } catch (e) { lastError = e; }
  }
  throw new Error("溯音咪咕失败: " + (lastError?.message || "unknown"));
}

// --- 溯音统一入口 ---
async function suyinGetUrl(platform, songId, quality, songInfo) {
  switch (platform) {
    case "tx": return suyinQQGetUrl(songInfo, quality);
    case "wy": return suyin163GetUrl(songInfo);
    case "kw": return suyinKuwoGetUrl(songInfo, quality);
    case "mg": return suyinMiguGetUrl(songInfo);
    default: throw new Error("溯音不支持该平台");
  }
}

// --- 长青SVIP ---
async function changqingGetUrl(platform, songId, quality, songInfo) {
  return buildTemplateUrl(platform, quality, songInfo, CHANGQING_URL_TEMPLATES, "长青SVIP");
}

// --- 念心SVIP ---
async function nianxinGetUrl(platform, songId, quality, songInfo) {
  return buildTemplateUrl(platform, quality, songInfo, NIANXIN_URL_TEMPLATES, "念心SVIP");
}

// --- 野花音源（从混淆代码逆向集成，作为备用兜底源） ---
async function yehuaGetUrl(platform, songId, quality, songInfo) {
  const id = getPlatformSongId(platform, songInfo);
  if (!id) throw new Error("野花缺少歌曲ID");

  // 野花音质映射
  var yehuaQualityMap = {
    "128k": "128k", "192k": "192k", "320k": "320k",
    "flac": "flac", "flac24bit": "flac", "24bit": "flac"
  };
  var q = yehuaQualityMap[quality] || "128k";

  var url = YEHUA_BASE_URL + "url/" + platform + "/" + encodeURIComponent(String(id)) + "/" + q;

  var res = await httpRequest(url, {
    method: "GET",
    timeout: GLOBAL_CONFIG.requestTimeout,
    headers: {
      "User-Agent": "LX-Music/2.8.0",
      "Accept": "*/*"
    }
  });

  var body = res.body;

  // 尝试多种响应格式解析
  if (typeof body === "string") {
    // 直接返回URL字符串
    if (HTTP_URL_REGEX.test(body.trim())) return body.trim();
    // 尝试JSON解析
    try {
      var parsed = JSON.parse(body);
      if (parsed && typeof parsed === "object") {
        if (parsed.url) return parsed.url;
        if (parsed.data && typeof parsed.data === "object") {
          if (parsed.data.url) return parsed.data.url;
          var item = Array.isArray(parsed.data) ? parsed.data[0] : parsed.data;
          if (item && item.url) return item.url;
        }
        if (parsed.code === 0 && parsed.msg) return parsed.msg;
      }
    } catch (e) { /* 非JSON，忽略 */ }
  } else if (body && typeof body === "object") {
    if (body.url) return body.url;
    if (body.data && typeof body.data === "object") {
      if (body.data.url) return body.data.url;
      var item2 = Array.isArray(body.data) ? body.data[0] : body.data;
      if (item2 && item2.url) return item2.url;
    }
    if (body.code === 0 && body.msg) return body.msg;
  }

  throw new Error("野花未返回可用URL");
}

// --- 汽水VIP ---
async function qishuiSearch(keyword, page, pageSize) {
  if (!keyword) return { isEnd: true, list: [] };
  var p = page || 1;
  var ps = pageSize || 30;
  var res = await httpGetWithFallback(QISHUI_API_HTTPS, {
    act: "search", keywords: keyword, page: p, pagesize: ps, type: "music"
  }, 15000);
  var list = Array.isArray(res?.data?.lists) ? res.data.lists : [];
  var total = res?.data?.total ? Number(res.data.total) : list.length;
  return {
    isEnd: list.length < ps,
    list: list.map(normalizeSongInfo),
    total: total
  };
}

async function qishuiGetUrl(songInfo, quality) {
  var songId = getSongId(songInfo);
  if (!songId) throw new Error("汽水VIP缺少歌曲ID");
  var res = await httpGetWithFallback(QISHUI_API_HTTPS, {
    act: "song", id: songId, quality: normalizeQuality(quality)
  }, 20000);
  var data = getFirstData(res);
  if (!data || !data.url) throw new Error("汽水VIP未返回可用URL");
  if (data.ekey) {
    var proxyRes = await httpPost(QISHUI_PROXY_API, {
      url: data.url,
      key: data.ekey,
      filename: data.filename || "KMusic",
      ext: data.fileExtension ? String(data.fileExtension) : "aac"
    }, 60000);
    if (Number(proxyRes?.code) === 200 && proxyRes?.url) return String(proxyRes.url);
    throw new Error("汽水VIP代理解密失败");
  }
  return String(data.url);
}

async function qishuiGetLyric(songInfo) {
  var songId = getSongId(songInfo);
  if (!songId) return { lyric: "" };
  var res = await httpGetWithFallback(QISHUI_API_HTTPS, { act: "song", id: songId }, 15000);
  var data = getFirstData(res);
  return { lyric: data && data.lyric ? String(data.lyric) : "" };
}

async function qishuiHandler(action, params) {
  params = params || {};
  if (action === "musicSearch" || action === "search") {
    return qishuiSearch(
      params.keyword ? String(params.keyword) : "",
      params.page ? Number(params.page) : 1,
      params.pagesize ? Number(params.pagesize) : 30
    );
  }
  if (action === "musicUrl") {
    if (!params.musicInfo) throw new Error("请求参数不完整");
    var url = await qishuiGetUrl(params.musicInfo, params.type);
    return validateUrl(url, "汽水VIP");
  }
  if (action === "lyric") return qishuiGetLyric(params.musicInfo || {});
  throw new Error("action not support");
}

// ===================== 音源注册表 =====================
var SOURCE_HANDLERS = {
  xinghai:       { name: "星海主",    fn: xinghaiMainGetUrl },
  suyinQQ:       { name: "溯音QQ",    fn: function(_, __, q, si) { return suyinGetUrl("tx", null, q, si); } },
  suyin163:      { name: "溯音163",   fn: function(_, __, q, si) { return suyinGetUrl("wy", null, q, si); } },
  suyinKuwo:     { name: "溯音酷我",  fn: function(_, __, q, si) { return suyinGetUrl("kw", null, q, si); } },
  suyinMigu:     { name: "溯音咪咕",  fn: function(_, __, q, si) { return suyinGetUrl("mg", null, q, si); } },
  xinghaiBackup: { name: "星海备",    fn: xinghaiBackupGetUrl },
  changqingVip:  { name: "长青SVIP",  fn: changqingGetUrl },
  nianxinVip:    { name: "念心SVIP",  fn: nianxinGetUrl },
  yehua:         { name: "野花音源",  fn: yehuaGetUrl },
};

// ===================== 智能链路构建（健康调度 + 平台优先级） =====================
function buildSourceChain(platform, quality) {
  // 获取所有启用的源
  var chain = [];
  var keys = Object.keys(SOURCE_HANDLERS);
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (SOURCE_SWITCHES[key] !== false) {
      chain.push({ key: key, name: SOURCE_HANDLERS[key].name, fn: SOURCE_HANDLERS[key].fn });
    }
  }

  // 按健康分降序排序（智能健康调度）
  if (GLOBAL_CONFIG.healthCheckEnabled) {
    chain.sort(function(a, b) {
      return getHealthScore(b.key) - getHealthScore(a.key);
    });
  }

  // 平台特定源优先级（确保最合适的源排在前面）
  var platformPriority = {
    tx: ["xinghai", "suyinQQ", "changqingVip", "nianxinVip", "xinghaiBackup", "yehua"],
    wy: ["xinghai", "suyin163", "changqingVip", "nianxinVip", "xinghaiBackup", "yehua"],
    kw: ["xinghai", "suyinKuwo", "changqingVip", "nianxinVip", "xinghaiBackup", "yehua"],
    kg: ["xinghai", "changqingVip", "nianxinVip", "xinghaiBackup", "yehua"],
    mg: ["xinghai", "suyinMigu", "changqingVip", "nianxinVip", "xinghaiBackup", "yehua"],
  };

  var priority = platformPriority[platform] || [];
  if (priority.length > 0) {
    chain.sort(function(a, b) {
      var aIdx = priority.indexOf(a.key);
      var bIdx = priority.indexOf(b.key);
      if (aIdx === -1 && bIdx === -1) return 0;
      if (aIdx === -1) return 1;
      if (bIdx === -1) return -1;
      return aIdx - bIdx;
    });
  }

  return chain;
}

// ===================== 带健康调度的Fallback获取（核心调度器） =====================
async function getUrlWithFallback(platform, songInfo, quality) {
  if (!platform || typeof platform !== "string" || !PLATFORM_QUALITIES[platform]) {
    throw new Error("无效的平台参数");
  }
  if (!songInfo || typeof songInfo !== "object") {
    throw new Error("无效的歌曲信息");
  }

  var resolvedQuality = quality || "128k";
  var selectedQuality = selectQuality(resolvedQuality, PLATFORM_QUALITIES[platform]);
  var songId = getHashOrMid(songInfo);
  var chain = buildSourceChain(platform, selectedQuality);

  if (!chain.length) throw new Error("未找到可用音源链（所有源已禁用）");

  var errors = [];

  // 包装handler，自动记录健康状态
  function wrappedCall(handler) {
    return handler.fn(platform, songId, selectedQuality, songInfo)
      .then(function(result) {
        recordSuccess(handler.key);
        return validateUrl(result, handler.name);
      })
      .catch(function(err) {
        recordFailure(handler.key);
        throw err;
      });
  }

  // 第一阶段：并发请求前N个健康源（竞速模式）
  var healthySources = [];
  for (var i = 0; i < chain.length; i++) {
    if (isSourceHealthy(chain[i].key)) {
      healthySources.push(chain[i]);
    }
  }
  var concurrentBatch = healthySources.slice(0, GLOBAL_CONFIG.concurrentSources);

  if (concurrentBatch.length > 0) {
    try {
      var promises = [];
      for (var j = 0; j < concurrentBatch.length; j++) {
        promises.push(wrappedCall(concurrentBatch[j]));
      }
      var url = await Promise.any(promises);
      if (url) return url;
    } catch (e) {
      // Promise.any 全部失败，收集错误
      if (e && e.errors) {
        for (var k = 0; k < e.errors.length; k++) {
          errors.push(e.errors[k].message || String(e.errors[k]));
        }
      } else {
        errors.push(e.message || String(e));
      }
    }
  }

  // 第二阶段：顺序尝试剩余源（兜底模式）
  var remainingStart = Math.min(GLOBAL_CONFIG.concurrentSources, healthySources.length);
  // 先尝试健康的剩余源
  for (var m = remainingStart; m < healthySources.length; m++) {
    try {
      var result = await wrappedCall(healthySources[m]);
      return result;
    } catch (e2) {
      errors.push(healthySources[m].name + ": " + (e2.message || String(e2)));
    }
  }
  // 再尝试不健康的源（最后的兜底）
  for (var n = 0; n < chain.length; n++) {
    if (!isSourceHealthy(chain[n].key)) {
      try {
        var result2 = await wrappedCall(chain[n]);
        return result2;
      } catch (e3) {
        errors.push(chain[n].name + ": " + (e3.message || String(e3)));
      }
    }
  }

  throw new Error("所有音源均失败: " + errors.join("; "));
}

// ===================== 音源配置与注册 =====================
var sourceConfig = {};

var platformKeys = Object.keys(PLATFORM_QUALITIES);
for (var i = 0; i < platformKeys.length; i++) {
  var p = platformKeys[i];
  sourceConfig[p] = {
    name: PLATFORM_NAMES[p],
    type: "music",
    actions: ["musicUrl"],
    qualitys: PLATFORM_QUALITIES[p]
  };
}

sourceConfig[QISHUI_SOURCE_ID] = {
  name: QISHUI_SOURCE_NAME,
  type: "music",
  actions: ["musicSearch", "musicUrl", "lyric"],
  qualitys: ["128k", "320k", "flac", "flac24bit"]
};

// ===================== 事件监听 =====================
on(EVENT_NAMES.request, function(args) {
  var action = args.action;
  var source = args.source;
  var info = args.info;

  // 全局开关检查
  if (!GLOBAL_CONFIG.enabled) {
    return Promise.reject(new Error("插件已通过全局开关禁用"));
  }

  // 汽水VIP独立处理
  if (source === QISHUI_SOURCE_ID) {
    if (!SOURCE_SWITCHES.qishui) {
      return Promise.reject(new Error("汽水VIP已禁用"));
    }
    return qishuiHandler(action, info);
  }

  // 仅处理musicUrl请求
  if (action !== "musicUrl") {
    return Promise.reject(new Error("action not support"));
  }
  if (!info || !info.musicInfo) {
    return Promise.reject(new Error("请求参数不完整"));
  }

  return getUrlWithFallback(source, info.musicInfo, info.type || "128k");
});

// ===================== 插件初始化 =====================
send(EVENT_NAMES.inited, {
  openDevTools: false,
  sources: sourceConfig
});

noop("v11智谱版初始化完成 | 聚合音源已就绪 | 智能健康调度 ✓ | 严格防错歌 ✓ | 全局开关 ✓ | 缓存优化 ✓ | 野花备用 ✓");
