/* global window */
// ============================================================================
// MELR · AVD / LIC-DSF — moteur de l'INDICATEUR COMPOSITE (CI) de capacité
// d'endettement (Cadre de viabilité de la dette des pays à faible revenu,
// FMI / Banque mondiale). Patron calqué sur window.STAR (star-calc.jsx).
// ----------------------------------------------------------------------------
// Le CI mesure la capacité d'un pays à porter sa dette, à partir de la CPIA,
// de la croissance, de la couverture des importations par les réserves (et de
// son carré), des envois de fonds et de la croissance mondiale. Formule et
// seuils OFFICIELS du cadre LIC-DSF 2017/18 (Guidance Note, FMI/BM) :
//
//   CI = 0.385·CPIA + 2.719·g + 4.052·r − 3.990·r² + 2.022·rem + 13.520·wg
//
//   ⚠ UNITÉS (les coefficients y sont calibrés — se référer au gabarit CI
//   officiel du FMI ; croissances et envois en FRACTION décimale, pas en %) :
//   CPIA : note CPIA Banque mondiale (échelle 1–6, niveau ; moyenne des 3
//          dernières années). ⚠ MÊME référentiel CPIA que le CEPIA/BFI du STAR
//          (cf. règle « CPIA = référentiel unique » de l'aide-mémoire).
//   g    : croissance réelle du PIB en FRACTION (0,05 = 5 %), moyenne 10 ans
//          (5 réalisés + 5 projetés)
//   r    : couverture des importations par les réserves = ratio réserves/imports
//          (ex. 0,30 ≈ 3,6 mois d'importations), moyenne 10 ans
//   rem  : envois de fonds des travailleurs en FRACTION du PIB (0,05 = 5 %),
//          moyenne 10 ans
//   wg   : croissance mondiale réelle en FRACTION (0,035 = 3,5 %), moyenne 10 ans
//
//   Exemple de validation (ordre de grandeur, type Sénégal) :
//   CPIA 3,6 · g 0,05 · r 0,30 · rem 0,09 · wg 0,032 → CI ≈ 2,9 → « Moyenne ».
//
//   Classification de la capacité d'endettement (fixe le jeu de seuils de dette) :
//     faible   : CI < 2.69
//     moyenne  : 2.69 ≤ CI ≤ 3.05
//     forte    : CI > 3.05
//
// ⚠ RÉVISION EN COURS (note de consultation FMI/BM du 2 juin 2026, consultation
//   close début juillet 2026) : suppression du critère VA dette/exportations,
//   ajout du GFN/PIB et des intérêts/recettes, RECALIBRAGE du CI, module long
//   terme climat. → coefficients ET seuils PARAMÉTRÉS (objet MODELS), jamais
//   codés en dur (règle transversale n°1 de l'aide-mémoire). Le futur modèle
//   « LIC-DSF-2026 » s'ajoutera comme une nouvelle entrée de MODELS.
//
// HONNÊTETÉ DU MODÈLE (même retenue que window.STAR) : ce moteur calcule le CI,
// sa DÉCOMPOSITION, la CLASSIFICATION (faible/moyenne/forte) et la SENSIBILITÉ.
// Il ne produit JAMAIS la notation officielle de risque de surendettement
// (faible / modéré / élevé / en surendettement) : celle-ci exige l'AVD complète
// (projections, tests de résistance, jugement d'équipe) et reste SAISIE, publiée
// par le FMI/BM. C'est cette retenue qui rend l'outil crédible auprès d'un
// ministère des Finances.
// ============================================================================

(function () {
  // Modèles de calcul du CI (extensible : la révision 2026 s'ajoutera ici).
  const MODELS = {
    "LIC-DSF-2018": {
      label: "LIC-DSF 2017/18",
      // Coefficients officiels du CI (Guidance Note FMI/BM).
      coef: {
        cpia:        0.385,
        growth:      2.719,
        importCov:   4.052,
        importCov2: -3.990,   // terme quadratique sur la couverture des importations
        remit:       2.022,
        worldGrowth: 13.520,
      },
      // faible < weak ≤ moyenne ≤ strong < forte
      thresholds: { weak: 2.69, strong: 3.05 },
    },
  };
  const DEFAULT_MODEL = "LIC-DSF-2018";

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

  // CI = Σ coef·variable (+ terme quadratique sur r). Renvoie la valeur ET la
  // contribution (en points) de chaque terme, pour la décomposition.
  function ci(inp, modelKey) {
    const m = MODELS[modelKey || DEFAULT_MODEL] || MODELS[DEFAULT_MODEL];
    const cpia = num(inp && inp.cpia);
    const g    = num(inp && inp.growth);
    const r    = num(inp && inp.importCov);
    const rem  = num(inp && inp.remit);
    const wg   = num(inp && inp.worldGrowth);
    if ([cpia, g, r, rem, wg].some((x) => x == null)) return null;
    const c = m.coef;
    const contrib = {
      cpia:        c.cpia * cpia,
      growth:      c.growth * g,
      importCov:   c.importCov * r,
      importCov2:  c.importCov2 * r * r,
      remit:       c.remit * rem,
      worldGrowth: c.worldGrowth * wg,
    };
    const value = contrib.cpia + contrib.growth + contrib.importCov
                + contrib.importCov2 + contrib.remit + contrib.worldGrowth;
    return {
      value, contrib,
      inputs: { cpia, growth: g, importCov: r, remit: rem, worldGrowth: wg },
      model: modelKey || DEFAULT_MODEL,
    };
  }

  // Classification de la capacité d'endettement (faible / moyenne / forte).
  // Ce n'est PAS la notation de risque de surendettement (cf. honnêteté du modèle).
  function classify(ciValue, modelKey) {
    const m = MODELS[modelKey || DEFAULT_MODEL] || MODELS[DEFAULT_MODEL];
    if (ciValue == null) return null;
    if (ciValue < m.thresholds.weak)   return { key: "weak",   fr: "Faible",  en: "Weak" };
    if (ciValue > m.thresholds.strong) return { key: "strong", fr: "Forte",   en: "Strong" };
    return { key: "medium", fr: "Moyenne", en: "Medium" };
  }

  // Sensibilité EXACTE : le CI est linéaire en chaque variable sauf `importCov`
  // (terme quadratique) ; on recalcule donc le CI complet en remplaçant la
  // variable, ce qui reste exact pour tous les champs. Signale aussi si la
  // variation fait CHANGER la classe de capacité d'endettement (franchissement
  // de seuil) — l'information la plus actionnable pour un ministère.
  function sensitivity(baseInp, field, newValue, modelKey) {
    const base = ci(baseInp, modelKey);
    if (!base) return null;
    const next = { ...baseInp, [field]: newValue };
    const after = ci(next, modelKey);
    if (!after) return null;
    const bClass = classify(base.value, modelKey);
    const aClass = classify(after.value, modelKey);
    return {
      before: base.value, after: after.value,
      delta: after.value - base.value,
      classBefore: bClass, classAfter: aClass,
      crossed: !!(bClass && aClass && bClass.key !== aClass.key),
    };
  }

  window.DSA = { MODELS, DEFAULT_MODEL, num, ci, classify, sensitivity };
})();
