/*!
 * @name 非常刀
 * @description 聚合音源，进群链接 https://t.me/gydjlfk
 * @version v4
 * @author 群主要进去
 */

const { EVENT_NAMES, request, on, send } = globalThis.lx

// ========== API 端点 ==========
const CHKSZ_API = 'https://api.chksz.top/api'
const XINGHAI_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 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_KW_API = 'https://oiapi.net/api/Kuwo'
const SUYIN_MG_API = 'https://api.xcvts.cn/api/music/migu'

// ========== 音质映射 ==========
const CHKSZ_LEVEL = { '128k': 'standard', '320k': 'exhigh', 'flac': 'lossless', 'flac24bit': 'jymaster' }
const CHKSZ_FALLBACK = {
  jymaster: ['jymaster', 'lossless', 'exhigh', 'standard'],
  lossless: ['lossless', 'exhigh', 'standard'],
  exhigh: ['exhigh', 'standard'],
  standard: ['standard'],
}
const XINGHAI_BR = { '128k': '128', '192k': '192', '320k': '320', 'flac': '740', 'flac24bit': '999' }
const XINGHAI_SRC = { wy: 'netease', tx: 'tencent', kw: 'kuwo', kg: 'kugou', mg: 'migu' }
const SUYIN_QQ_BR = { '128k': 7, '320k': 5, 'flac': 4, 'hires': 3, 'flac24bit': 1, 'master': 1 }
const SUYIN_KW_BR = { 'flac': 1, '320k': 5, '128k': 7 }

// ========== 长青/念心 URL 模板 ==========
const CHANGQING = {
  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 = {
  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',
}

// ========== 缓存 ==========
const cache = new Map()
const CACHE_TTL = 300000
const CACHE_MAX = 200

function cacheGet(key) {
  const c = cache.get(key)
  if (!c) return null
  if (Date.now() - c.ts > CACHE_TTL) { cache.delete(key); return null }
  return c.val
}

function cacheSet(key, val) {
  if (cache.size >= CACHE_MAX) cache.delete(cache.keys().next().value)
  cache.set(key, { val, ts: Date.now() })
}

// ========== 工具函数 ==========
function httpGet(url, { timeout = 10000, headers = {} } = {}) {
  return new Promise((resolve, reject) => {
    request(url, { method: 'GET', timeout, headers: { Accept: 'application/json', ...headers } }, (err, resp) => {
      if (err) return reject(new Error(err.message))
      try {
        resolve(typeof resp.body === 'string' ? JSON.parse(resp.body) : resp.body)
      } catch { reject(new Error('响应解析失败')) }
    })
  })
}

function validateUrl(url) {
  if (typeof url === 'string' && /^https?:\/\//.test(url)) return url
  throw new Error('无效URL')
}

function getSongId(info) {
  return (info.hash || info.songmid || info.id || info.rid || info.songId || '').toString()
}

function getQqSongId(info) {
  const mid = info.meta?.qq?.mid || info.meta?.mid || info.songmid || (typeof info.id === 'string' && !/^\d+$/.test(info.id) ? info.id : null)
  if (mid) return { type: 'mid', value: mid }
  const songid = info.meta?.qq?.songid || info.meta?.songid || info.id
  if (songid) return { type: 'songid', value: songid }
  return null
}

function qualityToLevel(q) {
  if (['flac', 'flac24bit', '24bit', 'hires', 'master'].includes(q)) return 'lossless'
  if (['320k', '192k'].includes(q)) return 'exhigh'
  return 'standard'
}

function cleanText(text) {
  if (!text) return ''
  return text.replace(/（[^）]*）/g, '').replace(/\([^)]*\)/g, '').replace(/\[[^\]]*\]/g, '')
    .replace(/\s+/g, '').replace(/[【】《》"""'''·,，。!！?？:：;；/\\|\-]/g, '').trim().toLowerCase()
}

function formatDuration(ms) {
  const sec = typeof ms === 'number' ? Math.floor(ms > 1000 ? ms / 1000 : ms) : 0
  if (sec <= 0) return '00:00'
  return `${Math.floor(sec / 60).toString().padStart(2, '0')}:${(sec % 60).toString().padStart(2, '0')}`
}

function buildSearchKeywords(info) {
  const kws = []
  if (info.singer) kws.push({ kw: `${info.name} ${info.singer}`, strict: true })
  if (info.albumName || info.album) kws.push({ kw: `${info.name} ${info.albumName || info.album}`, strict: true })
  kws.push({ kw: info.name, strict: false })
  return kws
}

function checkSongMatch(apiName, apiArtist, musicInfo) {
  const a = cleanText(apiName), b = cleanText(musicInfo.name || '')
  if (!a || !b || (!a.includes(b) && !b.includes(a))) return false
  const singer = cleanText(musicInfo.singer || '')
  if (singer) {
    const c = cleanText(apiArtist || '')
    if (c && !c.includes(singer) && !singer.includes(c)) return false
  }
  return true
}

// ========== Provider: CHKSZ (网易云) ==========
async function chkszGetUrl(info, quality) {
  const level = CHKSZ_LEVEL[quality] || 'standard'
  const levels = CHKSZ_FALLBACK[level] || ['standard']
  const id = getSongId(info)
  if (!id) throw new Error('缺少ID')
  for (const lv of levels) {
    try {
      const body = await httpGet(`${CHKSZ_API}/163_music?id=${id}&level=${lv}`, { headers: { Referer: 'https://cp.chksz.top/' } })
      if (body?.code === 200 && body.data?.url) return body.data.url
    } catch { continue }
  }
  throw new Error('CHKSZ失败')
}

// ========== Provider: 星海 (全平台) ==========
async function xinghaiGetUrl(platform, info, quality) {
  const source = XINGHAI_SRC[platform]
  const br = XINGHAI_BR[quality] || '320'
  const id = getSongId(info)
  if (!source || !id) throw new Error('参数缺失')
  const body = await httpGet(`${XINGHAI_API}&types=url&source=${source}&id=${encodeURIComponent(id)}&br=${br}`)
  return validateUrl(body?.url)
}

// ========== Provider: 溯音QQ ==========
async function suyinQQGetUrl(info, quality) {
  const qqId = getQqSongId(info)
  if (!qqId) throw new Error('缺少QQ歌曲ID')
  const startBr = SUYIN_QQ_BR[quality] || 5
  const brs = [...new Set([startBr, 4, 5, 7])]
  for (const br of brs) {
    try {
      const params = `key=${SUYIN_QQ_KEY}&type=json&br=${br}&n=1&${qqId.type}=${qqId.value}`
      const body = await httpGet(`${SUYIN_QQ_API}?${params}`)
      const url = body?.data?.music || body?.data?.url || extractUrlFromMsg(body?.data?.message || body?.message)
      if (url) return validateUrl(url)
    } catch { continue }
  }
  throw new Error('溯音QQ失败')
}

function extractUrlFromMsg(msg) {
  if (!msg) return null
  const m = msg.match(/https?:\/\/[^\s"'<>]+/)
  return m ? m[0] : null
}

// ========== Provider: 溯音163 ==========
async function suyin163GetUrl(info) {
  const id = getSongId(info)
  if (!id) throw new Error('缺少ID')
  const body = await httpGet(`${SUYIN_163_API}?id=${id}`)
  const data = Array.isArray(body?.data) ? body.data[0] : body?.data
  return validateUrl(data?.url)
}

// ========== Provider: 溯音酷我 (搜索式) ==========
async function suyinKwGetUrl(info, quality) {
  const br = SUYIN_KW_BR[quality] || 5
  for (const { kw, strict } of buildSearchKeywords(info)) {
    try {
      const body = await httpGet(`${SUYIN_KW_API}?msg=${encodeURIComponent(kw)}&n=1&br=${br}`)
      const url = body?.data?.url || extractUrlFromMsg(body?.data?.message || body?.message)
      if (url && (!strict || checkSongMatch(body?.data?.song || '', body?.data?.singer || '', info)))
        return validateUrl(url)
    } catch { continue }
  }
  throw new Error('溯音酷我失败')
}

// ========== Provider: 溯音咪咕 (搜索式) ==========
async function suyinMgGetUrl(info) {
  for (const { kw, strict } of buildSearchKeywords(info)) {
    try {
      const body = await httpGet(`${SUYIN_MG_API}?gm=${encodeURIComponent(kw)}&n=1&num=1&type=json`)
      if (body?.code === 200 && body?.music_url) {
        if (!strict || checkSongMatch(body.title || '', body.artist || '', info))
          return validateUrl(body.music_url)
      }
    } catch { continue }
  }
  throw new Error('溯音咪咕失败')
}

// ========== Provider: 模板URL (长青/念心) ==========
async function templateGetUrl(platform, info, quality, templates) {
  const tpl = templates[platform]
  if (!tpl) throw new Error('模板不支持该平台')
  const id = getSongId(info)
  if (!id) throw new Error('缺少ID')
  const level = qualityToLevel(quality)
  const url = tpl.replace('{id}', encodeURIComponent(id)).replace('{level}', level)
  const body = await httpGet(url)
  return validateUrl(body?.url || body?.data?.url || extractUrlFromMsg(typeof body === 'string' ? body : JSON.stringify(body)))
}

// ========== 回退链 ==========
const CHAINS = {
  wy: [
    { name: 'CHKSZ', fn: (si, q) => chkszGetUrl(si, q) },
    { name: '星海', fn: (si, q) => xinghaiGetUrl('wy', si, q) },
    { name: '溯音163', fn: (si, q) => suyin163GetUrl(si) },
    { name: '长青', fn: (si, q) => templateGetUrl('wy', si, q, CHANGQING) },
    { name: '念心', fn: (si, q) => templateGetUrl('wy', si, q, NIANXIN) },
  ],
  tx: [
    { name: '溯音QQ', fn: (si, q) => suyinQQGetUrl(si, q) },
    { name: '星海', fn: (si, q) => xinghaiGetUrl('tx', si, q) },
    { name: '长青', fn: (si, q) => templateGetUrl('tx', si, q, CHANGQING) },
    { name: '念心', fn: (si, q) => templateGetUrl('tx', si, q, NIANXIN) },
  ],
  kw: [
    { name: '星海', fn: (si, q) => xinghaiGetUrl('kw', si, q) },
    { name: '溯音酷我', fn: (si, q) => suyinKwGetUrl(si, q) },
    { name: '长青', fn: (si, q) => templateGetUrl('kw', si, q, CHANGQING) },
    { name: '念心', fn: (si, q) => templateGetUrl('kw', si, q, NIANXIN) },
  ],
  kg: [
    { name: '星海', fn: (si, q) => xinghaiGetUrl('kg', si, q) },
    { name: '长青', fn: (si, q) => templateGetUrl('kg', si, q, CHANGQING) },
    { name: '念心', fn: (si, q) => templateGetUrl('kg', si, q, NIANXIN) },
  ],
  mg: [
    { name: '星海', fn: (si, q) => xinghaiGetUrl('mg', si, q) },
    { name: '溯音咪咕', fn: (si, q) => suyinMgGetUrl(si) },
    { name: '长青', fn: (si, q) => templateGetUrl('mg', si, q, CHANGQING) },
    { name: '念心', fn: (si, q) => templateGetUrl('mg', si, q, NIANXIN) },
  ],
}

async function getUrlWithFallback(platform, songInfo, quality) {
  const chain = CHAINS[platform]
  if (!chain) throw new Error('不支持的平台')

  const key = `url_${platform}_${getSongId(songInfo)}_${quality}`
  const cached = cacheGet(key)
  if (cached) return cached

  // Phase 1: 前3个源并发竞速
  const concurrent = chain.slice(0, 3)
  try {
    const url = await Promise.any(concurrent.map(s => s.fn(songInfo, quality).then(validateUrl)))
    cacheSet(key, url)
    return url
  } catch {}

  // Phase 2: 剩余源顺序尝试
  for (const s of chain.slice(3)) {
    try {
      const url = validateUrl(await s.fn(songInfo, quality))
      cacheSet(key, url)
      return url
    } catch { continue }
  }

  throw new Error('所有音源均失败')
}

// ========== 事件处理 ==========
on(EVENT_NAMES.request, async ({ action, source, info }) => {
  try {
    switch (action) {
      case 'musicUrl': return await handleMusicUrl(source, info)
      case 'search': return await handleSearch(source, info)
      default: throw new Error('不支持的操作')
    }
  } catch (error) {
    console.error(`[非常刀] ${source} ${action} 错误:`, error.message)
    throw error
  }
})

async function handleMusicUrl(source, info) {
  if (!info?.musicInfo) throw new Error('需要歌曲信息')
  return await getUrlWithFallback(source, info.musicInfo, info.type || '128k')
}

// ========== 搜索 ==========
async function handleSearch(source, info) {
  if (!info?.keyword) throw new Error('需要搜索关键词')
  const keyword = info.keyword.trim()
  const limit = Math.min(info.limit || 20, 30)

  switch (source) {
    case 'wy': return await searchChksz(keyword, limit)
    case 'kw': return await searchKuwo(keyword, limit)
    case 'mg': return await searchMigu(keyword, limit)
    default: throw new Error('该平台不支持搜索')
  }
}

async function searchChksz(keyword, limit) {
  const body = await httpGet(`${CHKSZ_API}/163_search?keyword=${encodeURIComponent(keyword)}&limit=${limit}`, { headers: { Referer: 'https://cp.chksz.top/' } })
  if (body?.code !== 200) throw new Error('搜索失败')
  const items = Array.isArray(body.data) ? body.data : (body.data?.songs || [])
  if (!items.length) throw new Error('未找到相关歌曲')
  return items.slice(0, limit).map(s => ({
    name: s.name || '', singer: s.artists || '',
    albumName: typeof s.album === 'string' ? s.album : (s.album?.name || ''),
    id: s.id, source: 'wy', interval: formatDuration(s.duration),
    meta: { picture: s.picUrl || '', wy: { id: s.id, url_id: s.id, lyric_id: s.id } }
  }))
}

async function searchKuwo(keyword, limit) {
  const results = []
  for (let page = 1; results.length < limit && page <= 3; page++) {
    try {
      const body = await httpGet(`${SUYIN_KW_API}?msg=${encodeURIComponent(keyword)}&n=${page}`)
      const d = body?.data
      if (!d?.song) break
      results.push({
        name: d.song || '', singer: d.singer || '', albumName: d.album || '',
        id: d.rid || `kw_${Date.now()}_${page}`, source: 'kw',
        interval: formatDuration(d.duration || d.time),
        meta: { kw: { id: d.rid || d.id } }
      })
    } catch { break }
  }
  if (!results.length) throw new Error('未找到相关歌曲')
  return results
}

async function searchMigu(keyword, limit) {
  const results = []
  for (let page = 1; results.length < limit && page <= 3; page++) {
    try {
      const body = await httpGet(`${SUYIN_MG_API}?gm=${encodeURIComponent(keyword)}&n=${page}&num=1&type=json`)
      if (body?.code !== 200 || !body.title) break
      results.push({
        name: body.title || '', singer: body.artist || '', albumName: body.album || '',
        id: `mg_${Date.now()}_${page}`, source: 'mg', interval: body.duration || '00:00',
        meta: { mg: { id: body.id || '' } }
      })
    } catch { break }
  }
  if (!results.length) throw new Error('未找到相关歌曲')
  return results
}

// ========== 初始化 ==========
send(EVENT_NAMES.inited, {
  openDevTools: false,
  sources: {
    wy: { name: '网易云音乐', type: 'music', actions: ['musicUrl', 'search'], qualitys: ['128k', '320k', 'flac', 'flac24bit'], defaultQuality: 'flac' },
    tx: { name: 'QQ音乐', type: 'music', actions: ['musicUrl'], qualitys: ['128k', '320k', 'flac', 'flac24bit'] },
    kw: { name: '酷我音乐', type: 'music', actions: ['musicUrl', 'search'], qualitys: ['128k', '320k', 'flac'] },
    kg: { name: '酷狗音乐', type: 'music', actions: ['musicUrl'], qualitys: ['128k', '320k', 'flac', 'flac24bit'] },
    mg: { name: '咪咕音乐', type: 'music', actions: ['musicUrl', 'search'], qualitys: ['128k', '320k', 'flac'] },
  }
})

console.log('[非常刀] v4 已加载 - 网易/QQ/酷我/酷狗/咪咕 多源聚合')
