// ViG Command Center — calculation engine (pure logic)
(function () {
  const V = window.VIG;

  // unique generals by name (a name can appear in multiple troop sheets)
  function uniqueNames() {
    return [...new Set(V.generals.map(g => g.name))];
  }

  // best (highest power) record for a given name
  function bestByName(name) {
    return V.generals.filter(g => g.name === name).sort((a, b) => b.power - a.power)[0];
  }

  /* ---------- Covenant completion ----------
     A covenant needs its main + 3 partner generals owned (matched by name). */
  function covenantStatus(cov, ownedByName) {
    const members = [cov.main, cov.c1, cov.c2, cov.c3].filter(Boolean);
    const ownedFlags = members.map(n => ownedByName(n));
    const ownedCount = ownedFlags.filter(Boolean).length;
    const missing = members.filter((_, i) => !ownedFlags[i]);
    return {
      members, ownedCount, total: members.length,
      pct: Math.round((ownedCount / members.length) * 100),
      complete: ownedCount === members.length,
      missing,
    };
  }

  /* ---------- Covenant optimizer ----------
     Rank incomplete covenants by closeness + value of the buffs they unlock. */
  function buffValue(buff) {
    const m = (buff || '').match(/(-?\d+)%/);
    const mag = m ? Math.abs(parseInt(m[1])) : 5;
    let v = mag;
    if (/attack/i.test(buff)) v += 6;
    if (/march speed/i.test(buff)) v += 5;
    if (/in-rally|rally/i.test(buff)) v += 4;
    if (/hp/i.test(buff)) v += 3;
    if (/^enemy|-\d+%/i.test(buff)) v += 5; // debuffs valuable
    return v;
  }
  function optimizeCovenants(ownedByName, limit = 8) {
    return V.covenants
      .map(cov => {
        const s = covenantStatus(cov, ownedByName);
        if (s.complete) return null;
        const value = buffValue(cov.buff1) + buffValue(cov.buff2);
        // priority: nearly-complete + high buff value, fewer generals to chase
        const closeness = s.ownedCount / s.total;
        const score = closeness * 55 + (value / 40) * 30 + (1 / s.missing.length) * 15;
        return { cov, status: s, value, score: Math.round(score * 10) / 10 };
      })
      .filter(Boolean)
      .sort((a, b) => b.score - a.score)
      .slice(0, limit);
  }

  /* ---------- Compatibility (main + assistant synergy) ----------
     Synthesized from troop-type match, power tiers, and covenant overlap. */
  function compatScore(main, assist) {
    if (!main || !assist) return 0;
    let s = 50;
    if (main.type === assist.type) s += 22; else s -= 8;
    s += (assist.power / 100) * 18;          // strong assistant lifts the pair
    s += (main.power / 100) * 6;
    const buffSync = Math.min(main.totAtk, assist.totAtk) / 2200 * 10;
    s += buffSync;
    if (main.name === assist.name) s = 0;     // can't pair with self
    return Math.max(0, Math.min(100, Math.round(s)));
  }
  function bestAssistants(main, pool, n = 4) {
    return pool.filter(g => g.name !== main.name)
      .map(g => ({ g, score: compatScore(main, g) }))
      .sort((a, b) => b.score - a.score).slice(0, n);
  }

  /* ---------- Dragon fit for a troop type ---------- */
  function dragonFit(dragon, type) {
    const key = { Ground: 'totGround', Mounted: 'totMounted', Ranged: 'totRanged', Siege: 'totSiege' }[type];
    const troopBuff = Math.round((dragon[key] || 0) * 10) / 10;
    const ms = Math.round((dragon.totMS || 0) * 10) / 10;
    const lead = (dragon.atk + dragon.def + dragon.ldr) / 3;
    const fit = Math.min(100, Math.round(troopBuff / 2.4 + ms / 6 + (lead - 200) / 2 + 30));
    return { troopBuff, ms, lead: Math.round(lead), fit: Math.max(0, fit) };
  }
  function bestDragons(type, n = 5) {
    return V.dragons.map(d => ({ d, ...dragonFit(d, type) }))
      .sort((a, b) => b.fit - a.fit).slice(0, n);
  }

  /* ---------- March stats ---------- */
  function marchStats({ primary, assist, dragon, type }) {
    const z = { atk: 0, def: 0, hp: 0, ms: 0 };
    if (!primary) return z;
    let atk = primary.totAtk, def = primary.totDef, hp = primary.totLdr, ms = primary.msPct;
    if (assist) { atk += Math.round(assist.totAtk * 0.18); def += Math.round(assist.totDef * 0.18); hp += Math.round(assist.totLdr * 0.18); }
    if (dragon) {
      const f = dragonFit(dragon, type);
      atk += Math.round(f.troopBuff * 0.6); def += Math.round(f.troopBuff * 0.4);
      ms += Math.round(f.ms / 4);
    }
    return { atk, def, hp, ms };
  }

  window.CALC = {
    uniqueNames, bestByName, covenantStatus, optimizeCovenants,
    buffValue, compatScore, bestAssistants, dragonFit, bestDragons, marchStats,
  };
})();
