/* global window */
// ============================================================================
// MELR · MTDS / SDMT — indicateurs COÛT-RISQUE d'un portefeuille de dette et
// comparaison de stratégies d'endettement (Banque mondiale / FMI).
// ----------------------------------------------------------------------------
// Patron calqué sur window.STAR / window.DSA. À partir de la COMPOSITION d'un
// portefeuille (par instrument/tranche : encours, devise, type de taux,
// maturité, révision de taux, taux), calcule les indicateurs canoniques du
// cadre MTDS (Medium-Term Debt Management Strategy) :
//   • COÛT   : taux d'intérêt moyen pondéré ; dette/PIB ; service/recettes.
//   • RISQUE : ATM (Average Time to Maturity → risque de refinancement) ;
//              ATR (Average Time to Re-fixing → risque de taux) ; part à taux
//              variable ; part en devises (risque de change) ; % échéant ≤ 1 an ;
//              dette « re-fixée » ≤ 1 an (exposition au risque de taux).
// Définitions fidèles au manuel BM (MTDS Analytical Tool, millésime 2025) :
//   ATM = Σ(tᵢ·principalᵢ) / total ; ATR = pour la dette à taux fixe, temps
//   jusqu'à l'échéance ; pour la dette à taux variable, temps jusqu'à la
//   prochaine révision de taux (S), pondéré par les encours.
//
// ⚠ HONNÊTETÉ DU MODÈLE (même retenue que STAR/DSA) : ce moteur calcule les
// INDICATEURS coût-risque et CLASSE des stratégies candidates. Il ne reproduit
// PAS la SIMULATION pluriannuelle instrument par instrument sous scénarios de
// choc (taux, change) — c'est l'outil officiel Banque mondiale (MTDS-ABPT.xlsm)
// qui fait foi pour cela. Simplification assumée : chaque tranche est traitée
// avec une maturité moyenne représentant le calendrier de son principal.
// ============================================================================

(function () {
  const num = (v) => {
    const n = Number(v);
    return v == null || v === "" || Number.isNaN(n) ? null : n;
  };

  // Indicateurs coût-risque d'un portefeuille.
  // portfolio = [{ amount, currency:"dom"|"fx", rateType:"fixed"|"variable",
  //                maturity, refixing?, rate?, due1y? }]  (montants dans une même unité)
  // macro     = { gdp?, revenue?, debtService? }  (optionnel, pour les ratios)
  function indicators(portfolio, macro) {
    const items = (portfolio || []).map((x) => ({
      amount:   num(x.amount),
      currency: x.currency === "fx" ? "fx" : "dom",
      variable: x.rateType === "variable",
      maturity: num(x.maturity),
      refixing: num(x.refixing),
      rate:     num(x.rate),
      due1y:    num(x.due1y),
    })).filter((x) => x.amount != null && x.amount > 0);
    const total = items.reduce((s, x) => s + x.amount, 0);
    if (total <= 0) return null;

    let wMat = 0, wRef = 0, varAmt = 0, fxAmt = 0, wRate = 0, rateBase = 0;
    let due1y = 0, refix1y = 0, matKnown = 0;
    for (const x of items) {
      // ATR : dette variable → temps jusqu'à révision (refixing) ; dette fixe →
      // temps jusqu'à l'échéance (maturity). Repli robuste si une valeur manque.
      const ref = x.variable ? (x.refixing != null ? x.refixing : 0) : (x.maturity != null ? x.maturity : (x.refixing != null ? x.refixing : 0));
      if (x.maturity != null) { wMat += x.amount * x.maturity; matKnown += x.amount; }
      wRef += x.amount * ref;
      if (x.variable) varAmt += x.amount;
      if (x.currency === "fx") fxAmt += x.amount;
      if (x.rate != null) { wRate += x.amount * x.rate; rateBase += x.amount; }
      if (x.due1y != null) due1y += x.due1y;
      // Dette re-fixée ≤ 1 an = tout le variable + le principal fixe échéant ≤ 1 an.
      if (x.variable) refix1y += x.amount;
      else if (x.due1y != null) refix1y += x.due1y;
    }
    const g = macro && num(macro.gdp), rev = macro && num(macro.revenue), ds = macro && num(macro.debtService);
    return {
      total,
      atm:            matKnown > 0 ? wMat / matKnown : null,   // Average Time to Maturity (années)
      atr:            wRef / total,                            // Average Time to Re-fixing (années)
      shareVariable:  varAmt / total,                          // risque de taux (part variable)
      shareFx:        fxAmt / total,                           // risque de change (part devises)
      wavgRate:       rateBase > 0 ? wRate / rateBase : null,  // taux d'intérêt moyen pondéré (%)
      share1y:        due1y > 0 ? due1y / total : null,        // risque de refinancement (% échéant ≤ 1 an)
      refixShare1y:   refix1y / total,                         // dette re-fixée ≤ 1 an (% du total)
      debtToGdp:      g ? total / g : null,                    // dette / PIB
      serviceToRev:   (ds != null && rev) ? ds / rev : null,   // service de la dette / recettes
    };
  }

  // Compare des stratégies candidates. strategies = [{ name, portfolio, macro }].
  // Renvoie, pour chacune, ses indicateurs + des repères de « meilleure » valeur
  // (coût le plus bas, ATM le plus long, moins de change) pour l'arbitrage.
  function compare(strategies) {
    const rows = (strategies || []).map((s) => ({ name: s.name, ind: indicators(s.portfolio, s.macro) }))
      .filter((r) => r.ind);
    if (!rows.length) return { rows: [], best: {} };
    const best = {
      wavgRate:     minBy(rows, (r) => r.ind.wavgRate),   // coût le plus faible
      atm:          maxBy(rows, (r) => r.ind.atm),         // moins de risque de refinancement
      shareFx:      minBy(rows, (r) => r.ind.shareFx),     // moins de risque de change
      shareVariable:minBy(rows, (r) => r.ind.shareVariable),
      refixShare1y: minBy(rows, (r) => r.ind.refixShare1y),
    };
    return { rows, best };
  }
  function minBy(rows, f) { let b = null; for (const r of rows) { const v = f(r); if (v == null) continue; if (b == null || v < f(b)) b = r; } return b ? b.name : null; }
  function maxBy(rows, f) { let b = null; for (const r of rows) { const v = f(r); if (v == null) continue; if (b == null || v > f(b)) b = r; } return b ? b.name : null; }

  window.MTDS = { num, indicators, compare };
})();
