// Tempo — jauges du Tableau de bord : taux de réussite, profit factor, ratio gain/perte.
// Un seul composant rendu : DashGaugesRow (desktop, et mobile via la prop stack).

// Les valeurs sont formatées par les formateurs communs de format-prefs.jsx
// (charte §1 : fmtNum, fmtPct, fmtPF), chargé avant ce fichier.

// ─── Jauges compteur ──────────────────────────────────────────────
// Arc de demi-cercle SVG pur : fond neutre + remplissage proportionnel + valeur
// au centre + libellé de zone. L'arc prend la teinte vive de la zone ; le
// libellé prend la teinte « texte » (contraste ≥ 4,5:1 en clair et en sombre).
const DASH_TONES = {
  red:   { color: 'var(--dash-red)',   text: 'var(--red)' },
  amber: { color: 'var(--amber)',      text: 'var(--amber-text)' },
  green: { color: 'var(--dash-green)', text: 'var(--green)' },
};
// Aucune zone : indicateur sans valeur (« — »), arc vide et pas de libellé.
const DASH_ZONE_NONE = { label: '', color: 'var(--fg-3)', text: 'var(--fg-3)' };

// Zone d'une métrique sur l'échelle « 0 → 3+ » (profit factor).
// Seuils : < 1 perdant, 1–1,5 faible, 1,5–2 correct, ≥ 2 solide.
// Ils s'appliquent à la valeur affichée (arrondie à 2 décimales par dashShown),
// ici et non chez l'appelant : un ratio écrit « 1,50 » est toujours « Correct ».
function dashZoneRatio(v) {
  if (!Number.isFinite(v)) return { label: 'Solide', ...DASH_TONES.green }; // ∞ = aucune perte
  const r = dashShown(v, 2);
  if (r < 1)   return { label: 'Négatif', ...DASH_TONES.red };
  if (r < 1.5) return { label: 'Faible',  ...DASH_TONES.red };
  if (r < 2)   return { label: 'Correct', ...DASH_TONES.amber };
  return { label: 'Solide', ...DASH_TONES.green };
}

// Zone du ratio gain/perte : mêmes seuils que le profit factor, mais un ratio
// sous 1 n'est pas « négatif » (70 % de réussite avec un ratio de 0,8 reste
// gagnant) : il est seulement « faible ».
function dashZoneGainLoss(v) {
  const z = dashZoneRatio(v);
  return z.label === 'Négatif' ? { ...z, label: 'Faible' } : z;
}

// Zone du taux de réussite (0–100 %) : < 40 faible, 40–55 correct, ≥ 55 solide.
// Les seuils s'appliquent à la valeur affichée (arrondie à 1 décimale par
// dashShown, comme fmtPct), ici et non chez l'appelant : un taux écrit
// « 55,0 % » est « Solide » sur tous les écrans, qu'on passe 54,95 ou 55.
function dashZoneWinRate(pct) {
  const p = dashShown(Number(pct) || 0, 1);
  if (p < 40) return { label: 'Faible',  ...DASH_TONES.red };
  if (p < 55) return { label: 'Correct', ...DASH_TONES.amber };
  return { label: 'Solide', ...DASH_TONES.green };
}

function DashGauge({ label, display, frac, zone, sub }) {
  // Géométrie : demi-cercle, centre (60,64), rayon 46 → arc de (14,64) à (106,64).
  const R = 46, CX = 60, CY = 64, SW = 9;
  const arcLen = Math.PI * R; // ≈ 144,5
  const f = Math.max(0, Math.min(1, frac || 0));
  const d = `M ${CX - R} ${CY} A ${R} ${R} 0 0 1 ${CX + R} ${CY}`;
  // Valeur longue (« 100,0 % ») : corps réduit pour rester dans l'arc.
  const valueSize = String(display).length > 6 ? 16 : 19;
  return (
    <div className="card lift" style={{ padding: '16px 18px 14px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
      <div style={{ fontSize: 12.5, fontWeight: 600, letterSpacing: '-.01em', color: 'var(--fg-2)', alignSelf: 'flex-start' }}>{label}</div>
      <svg width="140" height="86" viewBox="0 0 120 74" style={{ display: 'block', marginTop: 6, overflow: 'visible' }}>
        {/* Piste */}
        <path d={d} fill="none" stroke="var(--bg-elev)" strokeWidth={SW} strokeLinecap="round" />
        {/* Graduations aux quarts */}
        {[0.25, 0.5, 0.75].map((p) => {
          const a = Math.PI * (1 - p);
          const x1 = CX + (R - SW / 2 - 2.5) * Math.cos(a), y1 = CY - (R - SW / 2 - 2.5) * Math.sin(a);
          const x2 = CX + (R + SW / 2 + 2.5) * Math.cos(a), y2 = CY - (R + SW / 2 + 2.5) * Math.sin(a);
          return <line key={p} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--line)" strokeWidth="1" />;
        })}
        {/* Remplissage — dasharray proportionnel à la fraction */}
        {f > 0 && (
          <path d={d} fill="none" stroke={zone.color} strokeWidth={SW} strokeLinecap="round"
            strokeDasharray={`${f * arcLen} ${arcLen + 20}`}
            style={{ transition: 'stroke-dasharray .7s var(--ease), stroke .3s var(--ease)' }} />
        )}
        {/* Valeur au centre */}
        <text x={CX} y={CY - 8} textAnchor="middle" className="num"
          style={{ fontSize: valueSize, fontWeight: 700, fill: 'var(--fg)', letterSpacing: '-.02em' }}>{display}</text>
        {zone.label && (
          <text x={CX} y={CY + 6} textAnchor="middle"
            style={{ fontSize: 9.5, fontWeight: 600, fill: zone.text || zone.color, letterSpacing: '.05em', textTransform: 'uppercase' }}>{zone.label}</text>
        )}
      </svg>
      {sub && <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginTop: 4, textAlign: 'center', lineHeight: 1.4 }}>{sub}</div>}
    </div>
  );
}

// Valeur d'un indicateur telle qu'elle s'affiche, arrondie à `dec` décimales
// (même arrondi que fmtNum / fmtPct / fmtPF). La zone et le remplissage d'une
// jauge se calculent sur cette valeur : un profit factor de 0,9957 s'écrit
// « 1,00 », il est donc dans la zone 1–1,5 et non « Négatif » ; un taux de
// 39,96 % s'écrit « 40,0 % », il est « Correct ». ∞ reste ∞.
// Les échelles (dashZoneRatio, dashZoneWinRate) appliquent elles-mêmes cet
// arrondi ; il est idempotent, les valeurs déjà arrondies passent inchangées.
function dashShown(v, dec) {
  if (!Number.isFinite(v)) return v;
  const p = Math.pow(10, dec);
  return Math.round(v * p * (1 + 8 * Number.EPSILON)) / p;
}

// Rangée des 3 jauges du Tableau de bord : taux de réussite, profit factor,
// ratio gain/perte. Échelle des ratios : 0 → 3+ mappée sur l'arc (au-delà de 3,
// l'arc est plein). `stack` (optionnel, mobile) : une jauge par ligne quand la
// largeur ne permet pas les trois côte à côte. Sans la prop, rendu desktop.
// Simple garde : sans trade, rien à afficher (et aucun hook exécuté pour rien —
// la mesure de largeur vit dans DashGaugesGrid, monté seulement avec des trades).
function DashGaugesRow({ stats, stack = false }) {
  if (!stats || !stats.count) return null;
  return <DashGaugesGrid stats={stats} stack={stack} />;
}

// Largeur minimale d'une jauge : l'arc de 140 px, les marges de la carte et de
// quoi lire le sous-titre sans le hacher.
const DASH_GAUGE_MIN = 190;

function DashGaugesGrid({ stats, stack }) {
  // usePgWidth (pages.jsx) est chargé après ce fichier, mais lu au rendu seulement.
  const [ref, width] = usePgWidth();
  const gap = stack ? 10 : 14;
  // Trois jauges côte à côte dès qu'elles tiennent, sinon une par ligne : jamais
  // « deux puis une ». Le rendu desktop garde toujours ses trois colonnes.
  const oneCol = stack && width < 3 * DASH_GAUGE_MIN + 2 * gap;
  const wr = dashShown(Number(stats.winRate) || 0, 1);
  const pf = dashShown(stats.profitFactor, 2);
  const wl = dashShown(stats.avgLoss > 0 ? stats.avgWin / stats.avgLoss : (stats.avgWin > 0 ? Infinity : 0), 2);
  // Taux de réussite = gagnants ÷ trades : les nuls (P&L à 0) comptent dans le
  // total, on les montre donc dans le sous-titre.
  const nuls = Number.isFinite(stats.breakeven) ? stats.breakeven : Math.max(0, stats.count - stats.wins - stats.losses);
  // Nombres au format français (charte §1) : « 1 246 G · 980 P ».
  const gp = `${fmtNum(stats.wins, 0)} G · ${fmtNum(stats.losses, 0)} P` + (nuls > 0 ? ` · ${fmtNum(nuls, 0)} nul${nuls > 1 ? 's' : ''}` : '');
  // Uniquement des nuls : ni gain ni perte, les deux ratios n'ont pas de valeur.
  const decided = stats.wins + stats.losses > 0;
  const ratioFrac = (v) => Number.isFinite(v) ? Math.min(1, v / 3) : 1;
  return (
    <div ref={ref} className="stagger" style={{ display: 'grid', gridTemplateColumns: oneCol ? 'minmax(0, 1fr)' : 'repeat(3, minmax(0, 1fr))', gap, marginBottom: stack ? 12 : 14 }}>
      <DashGauge label="Taux de réussite" display={fmtPct(wr, 1)}
        frac={wr / 100} zone={dashZoneWinRate(wr)} sub={gp} />
      <DashGauge label="Profit factor" display={decided ? fmtPF(pf, stats.count) : '—'}
        frac={decided ? ratioFrac(pf) : 0} zone={decided ? dashZoneRatio(pf) : DASH_ZONE_NONE}
        sub={'gains bruts / pertes brutes · échelle\u00A00\u2060–\u20603+'} />
      {/* Sans trade gagnant, le ratio (gain moyen ÷ perte moyenne) n'est pas
          défini : « — », comme le « Gain moyen — aucun gain » de Statistiques. */}
      <DashGauge label="Ratio gain/perte" display={!decided || !stats.wins ? '—' : (Number.isFinite(wl) ? fmtNum(wl, 2) : '∞')}
        frac={decided && stats.wins ? ratioFrac(wl) : 0} zone={decided && stats.wins ? dashZoneGainLoss(wl) : DASH_ZONE_NONE}
        sub={'gain moyen / perte moyenne · échelle\u00A00\u2060–\u20603+'} />
    </div>
  );
}

// dashZoneWinRate est l'échelle UNIQUE du taux de réussite (jauge du Tableau de
// bord, anneau des Stratégies) : mêmes seuils et mêmes couleurs partout, et
// seuils comparés à la valeur affichée (1 décimale), quel que soit l'appelant.
Object.assign(window, { DashGaugesRow, dashZoneWinRate });
