// StressTestPanel — Stress test taux a renouvellement (terme 5 ans)
// Vague 3 PR 3.2 (Plan Pro Courtier).
//
// Affiche 4 scenarios cote a cote (taux courant + 4.5% / 5.5% / 6.5%) sous
// forme de barres SVG inline. Pour chaque scenario : DSCR colore, cash flow
// mensuel et annuel. Encadre alerte sur le pire scenario et indication du
// break-even rate (taux maximum supportable avant DSCR < 1.10).
//
// Inputs : { listing, lang? }. Pas d'inputs utilisateur — le panneau lit le
// listing tel quel et utilise les hypotheses par defaut (mise 25%, amort 25
// ans, vacance 4%). L'utilisateur peut ajuster via le calculateur en direct
// du drawer / AnalyzePage ; ce panneau reste un "what if renouvellement".
//
// Convention : IIFE, React global, hooks aliases useSC/useMC.
// Expose window.StressTestPanel.

(function () {
  'use strict';

  const useSC = React.useState;
  const useMC = React.useMemo;

  function _fmtMoney(v) {
    if (v == null || !Number.isFinite(Number(v))) return '—';
    var n = Number(v);
    var sign = n < 0 ? '-' : '';
    var abs = Math.abs(Math.round(n)).toLocaleString('fr-CA');
    return sign + abs + ' $';
  }
  function _fmtMoneySigned(v) {
    if (v == null || !Number.isFinite(Number(v))) return '—';
    var n = Number(v);
    var sign = n >= 0 ? '+' : '-';
    var abs = Math.abs(Math.round(n)).toLocaleString('fr-CA');
    return sign + abs + ' $';
  }
  function _fmtPct(v, digits) {
    if (v == null || !Number.isFinite(Number(v))) return '—';
    return (Number(v) * 100).toFixed(digits == null ? 2 : digits) + ' %';
  }
  function _fmtRatio(v) {
    if (v == null || !Number.isFinite(Number(v))) return '—';
    return Number(v).toFixed(2);
  }

  // Memoisation simple par cle (listing.id + signature taux). Limite
  // intentionnelle a 32 entrees pour rester leger.
  var _cache = new Map();
  function _memoKey(listing, currentRate) {
    var id = (listing && (listing.id || listing.address)) || '_';
    return id + ':' + Number(currentRate || 0).toFixed(4);
  }
  function _memoCompute(listing, options) {
    if (!window.underwritingStress) return null;
    var key = _memoKey(listing, options && options.currentRate);
    if (_cache.has(key)) return _cache.get(key);
    var res = window.underwritingStress.calculateStressScenarios(listing, options || {});
    if (_cache.size > 32) {
      var firstKey = _cache.keys().next().value;
      _cache.delete(firstKey);
    }
    _cache.set(key, res);
    return res;
  }

  // ---- Sous-composants ---------------------------------------------------

  function ScenarioBar({ label, scenario, isCurrent, lang }) {
    if (!scenario) return null;
    var dscr = scenario.dscr;
    var tone = window.underwritingStress.dscrTone(dscr);
    var color = window.underwritingStress.dscrToneColor(tone);
    // Largeur de barre : DSCR / 2 * 100% (DSCR=2.0 -> 100% ; DSCR=0 -> 0%).
    var widthPct = Math.max(2, Math.min(100, (dscr / 2) * 100));
    var cf = scenario.monthlyCashflow;
    var cfYear = scenario.annualCashflow;

    return (
      <div style={{ marginBottom: 14 }}>
        <div style={{
          display: 'flex', justifyContent: 'space-between',
          alignItems: 'baseline', marginBottom: 4,
        }}>
          <div style={{ fontSize: 13, fontWeight: 600, color: '#0F172A' }}>
            {label}
            {isCurrent && (
              <span style={{
                marginLeft: 8, fontSize: 10, fontWeight: 500,
                background: '#e0f2fe', color: '#075985',
                padding: '1px 6px', borderRadius: 3,
              }}>
                {lang === 'en' ? 'CURRENT' : 'COURANT'}
              </span>
            )}
            <span style={{ marginLeft: 8, fontSize: 12, color: '#64748b', fontWeight: 400 }}>
              {_fmtPct(scenario.rate)}
            </span>
          </div>
          <div style={{ fontSize: 13, fontWeight: 600, color: color }}>
            DSCR {_fmtRatio(dscr)}
          </div>
        </div>
        <svg width="100%" height="22" style={{ display: 'block' }} role="img"
          aria-label={`DSCR ${_fmtRatio(dscr)} a ${_fmtPct(scenario.rate)}`}>
          <rect x="0" y="0" width="100%" height="22" rx="3" fill="#f1f5f9"/>
          <rect x="0" y="0" width={widthPct + '%'} height="22" rx="3" fill={color} opacity="0.85"/>
          {/* Repere DSCR = 1.10 (RCD min banque) */}
          <line x1="55%" y1="0" x2="55%" y2="22" stroke="#475569" strokeWidth="1" strokeDasharray="2,2" opacity="0.6"/>
        </svg>
        <div style={{
          display: 'flex', justifyContent: 'space-between',
          marginTop: 4, fontSize: 12, color: '#475569',
        }}>
          <span>
            {lang === 'en' ? 'Cash flow' : 'Cash flow'} :{' '}
            <strong style={{ color: cf >= 0 ? '#16a34a' : '#dc2626' }}>
              {_fmtMoneySigned(cf)}/{lang === 'en' ? 'mo' : 'mois'}
            </strong>
            {' '}({_fmtMoneySigned(cfYear)}/{lang === 'en' ? 'yr' : 'an'})
          </span>
          <span style={{ color: '#94a3b8' }}>
            {lang === 'en' ? 'Pmt' : 'Vers.'} {_fmtMoney(scenario.monthlyPayment)}/{lang === 'en' ? 'mo' : 'mois'}
          </span>
        </div>
      </div>
    );
  }

  function AlertBox({ result, lang }) {
    var fr = lang !== 'en';
    // On choisit le pire des 3 scenarios stress (4.5 / 5.5 / 6.5).
    var worst = [result.scenario45, result.scenario55, result.scenario65]
      .reduce(function (a, b) { return a.dscr < b.dscr ? a : b; });
    var tone = window.underwritingStress.dscrTone(worst.dscr);
    var color = window.underwritingStress.dscrToneColor(tone);
    var toneLabel = window.underwritingStress.dscrToneLabel(tone, lang);

    var bg = tone === 'safe' ? '#f0fdf4' : tone === 'warning' ? '#fffbeb' : '#fef2f2';
    var border = tone === 'safe' ? '#bbf7d0' : tone === 'warning' ? '#fde68a' : '#fecaca';

    var ratePct = (worst.rate * 100).toFixed(1) + ' %';
    var cfMonth = _fmtMoneySigned(worst.monthlyCashflow);
    var dscrStr = _fmtRatio(worst.dscr);

    var headline = fr
      ? 'Au renouvellement a ' + ratePct + ', votre cash flow tombe a ' + cfMonth +
        '/mois et le DSCR descend a ' + dscrStr + '.'
      : 'At renewal at ' + ratePct + ', cash flow drops to ' + cfMonth +
        '/mo and DSCR falls to ' + dscrStr + '.';

    return (
      <div style={{
        background: bg, border: '1px solid ' + border, borderRadius: 6,
        padding: '10px 12px', marginTop: 12,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', marginBottom: 6 }}>
          <span style={{
            background: color, color: '#fff', fontWeight: 700, fontSize: 11,
            padding: '2px 8px', borderRadius: 3, letterSpacing: 0.5,
          }}>{toneLabel}</span>
        </div>
        <div style={{ fontSize: 13, color: '#0F172A', lineHeight: 1.5 }}>
          {headline}
        </div>
      </div>
    );
  }

  function BreakEvenLine({ result, lang }) {
    var fr = lang !== 'en';
    if (!result.breakEvenRate || result.breakEvenRate <= 0) {
      return (
        <div style={{ fontSize: 12, color: '#dc2626', marginTop: 10, fontStyle: 'italic' }}>
          {fr
            ? 'Ce prix d\'achat ne permet aucun taux raisonnable avec DSCR ≥ 1.10. Revoyez le prix offert.'
            : 'This purchase price does not support any reasonable rate with DSCR ≥ 1.10. Revisit the offer.'}
        </div>
      );
    }
    var pct = (result.breakEvenRate * 100).toFixed(2) + ' %';
    return (
      <div style={{ fontSize: 12, color: '#475569', marginTop: 10 }}>
        {fr
          ? 'Votre prix d\'achat reste rentable (DSCR ≥ 1.10) jusqu\'a '
          : 'Your purchase price stays viable (DSCR ≥ 1.10) up to '}
        <strong style={{ color: '#0F172A' }}>{pct}</strong>
        {fr ? ' de taux hypothecaire.' : ' mortgage rate.'}
      </div>
    );
  }

  // ---- Composant principal ----------------------------------------------

  function StressTestPanel({ listing, lang }) {
    var l = lang || 'fr';
    var fr = l !== 'en';

    if (!window.underwritingStress) {
      return null;
    }

    var result = useMC(function () {
      return _memoCompute(listing, {});
    }, [listing && listing.id, listing && listing.price, listing && listing.asking_gross_income]);

    if (!result) {
      return (
        <section style={{ margin: '20px 0' }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, color: '#0F172A', margin: '0 0 8px' }}>
            {fr ? 'Stress test taux a renouvellement' : 'Rate renewal stress test'}
          </h3>
          <div style={{ fontSize: 12, color: '#94a3b8', fontStyle: 'italic' }}>
            {fr
              ? 'Donnees insuffisantes pour calculer le stress test (prix ou revenus manquants).'
              : 'Insufficient data to compute stress test (price or income missing).'}
          </div>
        </section>
      );
    }

    return (
      <section id="section-stress-renewal" style={{ margin: '20px 0' }}>
        <h3 style={{
          fontSize: 14, fontWeight: 600, color: '#0F172A',
          margin: '0 0 4px', display: 'flex', alignItems: 'baseline', gap: 8,
        }}>
          {fr ? 'Stress test taux a renouvellement' : 'Rate renewal stress test'}
          <small style={{ fontSize: 11, fontWeight: 400, color: '#64748b' }}>
            ({fr ? 'terme ' : 'term '}{result.termYears} {fr ? 'ans' : 'yrs'})
          </small>
        </h3>
        <p style={{ fontSize: 12, color: '#64748b', margin: '0 0 12px', lineHeight: 1.5 }}>
          {fr
            ? 'Que devient le cash flow et le DSCR si le taux remonte au renouvellement ? Les banques exigent un DSCR ≥ 1.10 pour renouveler — la ligne pointillee marque ce seuil.'
            : 'What happens to cash flow and DSCR if the rate rises at renewal? Banks require DSCR ≥ 1.10 to renew — the dashed line marks that threshold.'}
        </p>

        <div>
          <ScenarioBar
            label={fr ? 'Taux courant' : 'Current rate'}
            scenario={result.current}
            isCurrent={true}
            lang={l}/>
          <ScenarioBar
            label={fr ? 'Scenario 4,5 %' : 'Scenario 4.5%'}
            scenario={result.scenario45} lang={l}/>
          <ScenarioBar
            label={fr ? 'Scenario 5,5 %' : 'Scenario 5.5%'}
            scenario={result.scenario55} lang={l}/>
          <ScenarioBar
            label={fr ? 'Scenario 6,5 %' : 'Scenario 6.5%'}
            scenario={result.scenario65} lang={l}/>
        </div>

        <AlertBox result={result} lang={l}/>
        <BreakEvenLine result={result} lang={l}/>

        <div style={{ fontSize: 11, color: '#94a3b8', marginTop: 10, lineHeight: 1.4 }}>
          {fr
            ? 'Hypotheses : mise de fonds ' + Math.round(result.context.downPaymentPct * 100) +
              ' %, amortissement ' + result.context.amortYears + ' ans, vacance ' +
              Math.round(result.context.vacancyPct * 100) + ' %.'
            : 'Assumptions: ' + Math.round(result.context.downPaymentPct * 100) +
              '% down, ' + result.context.amortYears + '-yr amort, ' +
              Math.round(result.context.vacancyPct * 100) + '% vacancy.'}
        </div>
      </section>
    );
  }

  window.StressTestPanel = StressTestPanel;
})();
