/* global React */
const { useState, useMemo, useEffect, useRef } = React;

// ───────── i18n ─────────
const STRINGS = {
  en: {
    brandSub: '1st-year ROI calculator',
    inputsEyebrow: '01 · Inputs',
    inputsTitle: 'Deal & economics',
    dealName: 'Deal name',
    dealPh: 'Acme Corp · Annual license',
    operativeCost: 'Operative cost',
    operativeHint: '— total cost to deliver',
    roiLabel: 'Expected 1st-year ROI',
    roiHint: "— customer's return",
    notes: 'Notes & justification',
    formulasHead: 'Formulas',
    floor: 'Floor',
    ceiling: 'Ceiling',
    price: 'Price',
    floorEq: 'cost × markup',
    ceilingEq: 'ROI × share',
    priceEq: 'avg(floor, ceiling)',
    reset: 'Reset',
    copy: 'Copy summary',
    decisionEyebrow: '02 · Decision matrix',
    decisionTitle: 'Four scenarios — pick a quadrant',
    band: 'Reasonable band',
    roiPill: 'ROI',
    recommended: 'Recommended',
    minViable: 'Min viable',
    roiCeiling: 'ROI ceiling',
    margin: 'Margin',
    ofRoi: 'Of ROI',
    commitEyebrow: '03 · Commit',
    commitTitle: 'Final price',
    finalPrice: 'Final price',
    floorMark: 'Floor',
    bandMark: 'Reasonable band',
    ceilingMark: 'Ceiling',
    verdict: 'Verdict',
    vReasonable: 'Reasonable',
    vBelow: 'Below floor — risky',
    vHigh: 'High ROI capture — push back may come',
    vConservative: 'Conservative — leaving value on the table',
    statMargin: 'Margin',
    statCost: 'Cost as % of price',
    statRoi: '% of customer ROI',
    statNet: 'Customer net gain',
    sensHead: 'Sensitivity — markup × ROI share',
    sumDeal: 'Deal',
    sumCost: 'Operative cost',
    sumRoi: 'Expected 1st-year ROI',
    sumPrice: 'Recommended price',
    sumNotes: 'Notes',
    notesPh: 'Pilot ran 6 weeks. Champion: VP Ops. Replacing 2 legacy tools.',
    dealDefault: 'Acme Corp · Annual license',
  },
  es: {
    brandSub: 'Calculadora de ROI a 1 año',
    inputsEyebrow: '01 · Datos',
    inputsTitle: 'Cliente y economía',
    dealName: 'Nombre del trato',
    dealPh: 'Acme S.A. · Licencia anual',
    operativeCost: 'Costo operativo',
    operativeHint: '— costo total de entrega',
    roiLabel: 'ROI esperado a 1 año',
    roiHint: '— retorno del cliente',
    notes: 'Notas y justificación',
    formulasHead: 'Fórmulas',
    floor: 'Piso',
    ceiling: 'Techo',
    price: 'Precio',
    floorEq: 'costo × multiplicador',
    ceilingEq: 'ROI × participación',
    priceEq: 'prom(piso, techo)',
    reset: 'Reiniciar',
    copy: 'Copiar resumen',
    decisionEyebrow: '02 · Matriz de decisión',
    decisionTitle: 'Cuatro escenarios — elige un cuadrante',
    band: 'Rango razonable',
    roiPill: 'ROI',
    recommended: 'Recomendado',
    minViable: 'Mínimo viable',
    roiCeiling: 'Techo ROI',
    margin: 'Margen',
    ofRoi: 'Del ROI',
    commitEyebrow: '03 · Definir',
    commitTitle: 'Precio final',
    finalPrice: 'Precio final',
    floorMark: 'Piso',
    bandMark: 'Rango razonable',
    ceilingMark: 'Techo',
    verdict: 'Veredicto',
    vReasonable: 'Razonable',
    vBelow: 'Bajo el piso — arriesgado',
    vHigh: 'Captura de ROI alta — puede haber resistencia',
    vConservative: 'Conservador — dejando valor sobre la mesa',
    statMargin: 'Margen',
    statCost: 'Costo como % del precio',
    statRoi: '% del ROI del cliente',
    statNet: 'Ganancia neta del cliente',
    sensHead: 'Sensibilidad — multiplicador × participación ROI',
    sumDeal: 'Trato',
    sumCost: 'Costo operativo',
    sumRoi: 'ROI esperado a 1 año',
    sumPrice: 'Precio recomendado',
    sumNotes: 'Notas',
    notesPh: 'Piloto de 6 semanas. Sponsor: VP de Operaciones. Reemplaza 2 herramientas heredadas.',
    dealDefault: 'Acme S.A. · Licencia anual',
  },
};

// ───────── Number helpers ─────────
const fmtMoney = (n, currency = 'USD', decimals = 0) => {
  if (!Number.isFinite(n)) return '—';
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(n);
};
const fmtPct = (n, decimals = 1) => {
  if (!Number.isFinite(n)) return '—';
  return `${(n * 100).toFixed(decimals)}%`;
};
const parseNum = (s) => {
  if (typeof s === 'number') return s;
  const cleaned = String(s).replace(/[^0-9.\-]/g, '');
  const v = parseFloat(cleaned);
  return Number.isFinite(v) ? v : 0;
};

// ───────── Number input ─────────
function MoneyInput({ value, onChange, prefix = '$', placeholder, autoFocus }) {
  const display = value === '' || value == null ? '' : Number(value).toLocaleString('en-US');
  return (
    <div className="money-input">
      <span className="money-prefix">{prefix}</span>
      <input
        type="text"
        inputMode="decimal"
        value={display}
        placeholder={placeholder}
        autoFocus={autoFocus}
        onChange={(e) => onChange(parseNum(e.target.value))}
      />
    </div>
  );
}

// ───────── Quadrant card ─────────
function QuadrantCard({ markup, share, cost, roi, currency, decimals, selected, onSelect, t }) {
  const minViable = cost * markup;            // cost-based price
  const roiPrice = roi * share;               // ROI-share-based price
  const recommended = (minViable + roiPrice) / 2;
  const margin = recommended > 0 ? (recommended - cost) / recommended : 0;
  const roiShareOfReturn = roi > 0 ? recommended / roi : 0;

  return (
    <button
      type="button"
      className={`quad ${selected ? 'is-selected' : ''}`}
      onClick={onSelect}
    >
      <div className="quad-head">
        <div className="quad-tag">
          <span className="quad-pill">×{markup.toFixed(2)}</span>
          <span className="quad-pill">{(share * 100).toFixed(0)}% {t.roiPill}</span>
        </div>
        <div className={`quad-dot ${selected ? 'is-on' : ''}`} aria-hidden="true" />
      </div>

      <div className="quad-price">
        <div className="quad-price-label">{t.recommended}</div>
        <div className="quad-price-value mono">{fmtMoney(recommended, currency, decimals)}</div>
      </div>

      <div className="quad-rows">
        <div className="quad-row">
          <span className="quad-row-label">{t.minViable}</span>
          <span className="quad-row-bar">
            <span className="bar-track"><span className="bar-fill" style={{ width: `${Math.min(100, (minViable / Math.max(minViable, roiPrice)) * 100)}%` }} /></span>
          </span>
          <span className="quad-row-value mono">{fmtMoney(minViable, currency, decimals)}</span>
        </div>
        <div className="quad-row">
          <span className="quad-row-label">{t.roiCeiling}</span>
          <span className="quad-row-bar">
            <span className="bar-track"><span className="bar-fill alt" style={{ width: `${Math.min(100, (roiPrice / Math.max(minViable, roiPrice)) * 100)}%` }} /></span>
          </span>
          <span className="quad-row-value mono">{fmtMoney(roiPrice, currency, decimals)}</span>
        </div>
      </div>

      <div className="quad-foot">
        <div><span className="foot-label">{t.margin}</span> <span className="mono">{fmtPct(margin, 1)}</span></div>
        <div><span className="foot-label">{t.ofRoi}</span> <span className="mono">{fmtPct(roiShareOfReturn, 1)}</span></div>
      </div>
    </button>
  );
}

// ───────── Decision slider ─────────
function DecisionSlider({ min, max, value, onChange, currency, decimals, t, pulse }) {
  const pct = max > min ? ((value - min) / (max - min)) * 100 : 50;
  return (
    <div className={`decider ${pulse ? 'is-ai-applied' : ''}`}>
      <div className="decider-head">
        <div>
          <div className="decider-label">{t.finalPrice}</div>
          <div className="decider-value mono">{fmtMoney(value, currency, decimals)}</div>
        </div>
        <div className="decider-bounds">
          <span className="mono">{fmtMoney(min, currency, decimals)}</span>
          <span className="decider-bounds-sep">→</span>
          <span className="mono">{fmtMoney(max, currency, decimals)}</span>
        </div>
      </div>
      <div className="decider-track">
        <div className="decider-fill" style={{ width: `${pct}%` }} />
        <div className="decider-thumb" style={{ left: `${pct}%` }} />
        <input
          type="range"
          min={min}
          max={max}
          step={Math.max(1, (max - min) / 1000)}
          value={value}
          onChange={(e) => onChange(parseFloat(e.target.value))}
        />
      </div>
      <div className="decider-marks">
        <span>{t.floorMark}</span>
        <span>{t.bandMark}</span>
        <span>{t.ceilingMark}</span>
      </div>
    </div>
  );
}

// ───────── Verdict ─────────
function Verdict({ price, cost, roi, t }) {
  const margin = price > 0 ? (price - cost) / price : 0;
  const payback = price > 0 ? cost / price : 0;
  const captured = roi > 0 ? price / roi : 0;

  let tone = 'neutral';
  let label = t.vReasonable;
  if (price < cost * 1.15) { tone = 'warn'; label = t.vBelow; }
  else if (captured > 0.25) { tone = 'warn'; label = t.vHigh; }
  else if (captured < 0.10) { tone = 'low'; label = t.vConservative; }
  else { tone = 'good'; label = t.vReasonable; }

  return (
    <div className={`verdict tone-${tone}`}>
      <div className="verdict-row">
        <div className="verdict-label">{t.verdict}</div>
        <div className="verdict-status">{label}</div>
      </div>
      <div className="verdict-stats">
        <div><div className="stat-k">{t.statMargin}</div><div className="stat-v mono">{fmtPct(margin, 1)}</div></div>
        <div><div className="stat-k">{t.statCost}</div><div className="stat-v mono">{fmtPct(payback, 1)}</div></div>
        <div><div className="stat-k">{t.statRoi}</div><div className="stat-v mono">{fmtPct(captured, 1)}</div></div>
        <div><div className="stat-k">{t.statNet}</div><div className="stat-v mono">{fmtPct(roi > 0 ? (roi - price) / roi : 0, 1)}</div></div>
      </div>
    </div>
  );
}

// ───────── Sensitivity strip ─────────
function Sensitivity({ cost, roi, markups, shares, currency, decimals, onPick, finalPrice, t }) {
  const cells = [];
  for (const m of markups) {
    for (const s of shares) {
      const minViable = cost * m;
      const roiPrice = roi * s;
      const rec = (minViable + roiPrice) / 2;
      cells.push({ m, s, rec });
    }
  }
  const max = Math.max(...cells.map((c) => c.rec), 1);
  return (
    <div className="sens">
      <div className="sens-head">{t.sensHead}</div>
      <div className="sens-grid" style={{ gridTemplateColumns: `auto repeat(${shares.length}, 1fr)` }}>
        <div />
        {shares.map((s) => <div key={`h${s}`} className="sens-h mono">{(s * 100).toFixed(0)}%</div>)}
        {markups.map((m) => (
          <React.Fragment key={`r${m}`}>
            <div className="sens-h mono">×{m.toFixed(2)}</div>
            {shares.map((s) => {
              const minViable = cost * m;
              const roiPrice = roi * s;
              const rec = (minViable + roiPrice) / 2;
              const intensity = rec / max;
              const isPicked = Math.abs(rec - finalPrice) < 0.01;
              return (
                <button
                  key={`c${m}${s}`}
                  type="button"
                  className={`sens-cell ${isPicked ? 'is-picked' : ''}`}
                  style={{ '--intensity': intensity }}
                  onClick={() => onPick(rec)}
                >
                  <span className="mono">{fmtMoney(rec, currency, decimals)}</span>
                </button>
              );
            })}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

// ───────── EstimatorDrawer — floating panel with persistent chat ─────────
function EstimatorDrawer({ lang, modelSelection, onApplyEstimate }) {
  const [open, setOpen] = React.useState(false);
  const [pulse, setPulse] = React.useState(false);
  const [drawerMessages, setDrawerMessages] = React.useState(null);

  const handleApply = (vals) => {
    onApplyEstimate(vals);
    if (window._drawerMessages) setDrawerMessages([...window._drawerMessages]);
    setPulse(true);
    setTimeout(() => setPulse(false), 1200);
  };

  // Read live from window._estimatorMessages when opening
  const handleOpen = () => {
    // Prefer drawer-specific messages if they exist, otherwise use Phase 00 history
    const msgs = window._drawerMessages?.length
      ? [...window._drawerMessages]
      : window._estimatorMessages?.length
        ? [...window._estimatorMessages]
        : null;
    setDrawerMessages(msgs);
    setOpen(true);
  };

  const label = lang === 'es' ? 'Estimador' : 'Estimator';
  const hint  = lang === 'es' ? 'Ajusta costos y ROI' : 'Refine costs & ROI';

  return (
    <>
      {/* Toggle button */}
      <button
        className={`est-drawer-toggle ${open ? 'is-open' : ''} ${pulse ? 'is-pulse' : ''}`}
        onClick={() => open ? setOpen(false) : handleOpen()}
        title={hint}
      >
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
        </svg>
        <span>{label}</span>
        {pulse && <span className="est-drawer-dot" />}
      </button>

      {/* Drawer panel */}
      {open && (
        <div className="est-drawer-panel">
          <div className="est-drawer-header">
            <div>
              <div className="est-phase-eyebrow" style={{marginBottom:'2px'}}>
                {lang === 'es' ? 'Chat de estimación' : 'Estimation chat'}
              </div>
              <div style={{fontSize:'12px',color:'var(--fg-muted,#6B7280)'}}>
                {lang === 'es'
                  ? 'Refina supuestos — los valores se actualizan automáticamente'
                  : 'Refine assumptions — values update automatically'}
              </div>
            </div>
            <button className="est-btn-ghost small" onClick={() => setOpen(false)}>✕</button>
          </div>
          <window.Estimator
            lang={lang}
            modelSelection={modelSelection}
            initialMessages={drawerMessages}
            onApplyEstimate={handleApply}
            onSkip={() => setOpen(false)}
            compact={true}
          />
        </div>
      )}
    </>
  );
}

// ───────── AuditPanel — collapsible estimation breakdown ─────────────────
function AuditPanel({ costBreakdown, roiBreakdown, cost, roi, lang }) {
  const [open, setOpen] = React.useState(false);
  const fmt = (n) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(n);

  const title    = lang === 'es' ? 'Desglose de estimación' : 'Estimation breakdown';
  const costLbl  = lang === 'es' ? 'Costo operativo' : 'Operative cost';
  const roiLbl   = lang === 'es' ? 'ROI a 1 año' : '1st-year ROI';
  const showLbl  = lang === 'es' ? 'Ver desglose de la IA' : 'View AI breakdown';
  const hideLbl  = lang === 'es' ? 'Ocultar desglose' : 'Hide breakdown';

  return (
    <div className="audit-panel">
      <button className="audit-toggle" onClick={() => setOpen(v => !v)}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
          style={{transform: open ? 'rotate(90deg)' : 'rotate(0deg)', transition:'transform .2s'}}>
          <polyline points="9 18 15 12 9 6"/>
        </svg>
        <span>{open ? hideLbl : showLbl}</span>
        <span className="audit-tag">{title}</span>
      </button>
      {open && (
        <div className="audit-body">
          <div className="audit-row">
            <div className="audit-col">
              <div className="audit-col-label">{costLbl} — {fmt(cost)}</div>
              <div className="audit-col-text">{costBreakdown || '—'}</div>
            </div>
            <div className="audit-col">
              <div className="audit-col-label">{roiLbl} — {fmt(roi)}</div>
              <div className="audit-col-text">{roiBreakdown || '—'}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ───────── Main app ─────────
function App({ prefill = null, onReset = null, estimatorMessages = null, estimateLang = null, modelSelection = 'standard' }) {
  const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
    "currency": "USD",
    "markupLow": 1.20,
    "markupHigh": 1.25,
    "shareLow": 0.15,
    "shareHigh": 0.20,
    "decimals": 0,
    "showSensitivity": true,
    "lang": "en"
  }/*EDITMODE-END*/;

  const tweaks = window.useTweaks ? window.useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];
  const [tweak, setTweak] = tweaks;

  useEffect(() => {
    if (estimateLang) setTweak('lang', estimateLang);
  }, [estimateLang]);

  const t = STRINGS[tweak.lang] || STRINGS.en;

  const [cost, setCost] = useState(prefill?.cost ?? 48000);
  const [roi, setRoi] = useState(prefill?.roi ?? 180000);
  const [deal, setDeal] = useState(prefill?.deal || STRINGS.en.dealDefault);
  const [notes, setNotes] = useState(STRINGS.en.notesPh);

  const lastLang = useRef(tweak.lang);
  useEffect(() => {
    // Auto-translate placeholder content if user hasn't customized it
    const prevLang = lastLang.current;
    if (prevLang === tweak.lang) return;
    const prev = STRINGS[prevLang];
    if (deal === prev.dealDefault) setDeal(t.dealDefault);
    if (notes === prev.notesPh) setNotes(t.notesPh);
    lastLang.current = tweak.lang;
  }, [tweak.lang]);
  const [selected, setSelected] = useState({ m: tweak.markupHigh, s: tweak.shareLow });
  const [finalPrice, setFinalPrice] = useState(null);
  const [aiOpen, setAiOpen] = useState(false);
  const [aiPulse, setAiPulse] = useState(false);

  const quadrants = useMemo(() => {
    const list = [];
    for (const m of [tweak.markupLow, tweak.markupHigh]) {
      for (const s of [tweak.shareLow, tweak.shareHigh]) {
        const minViable = cost * m;
        const roiPrice = roi * s;
        const rec = (minViable + roiPrice) / 2;
        list.push({ m, s, minViable, roiPrice, rec });
      }
    }
    return list;
  }, [cost, roi, tweak.markupLow, tweak.markupHigh, tweak.shareLow, tweak.shareHigh]);

  const band = useMemo(() => {
    const recs = quadrants.map((q) => q.rec);
    return { min: Math.min(...recs), max: Math.max(...recs) };
  }, [quadrants]);

  const aiCtx = useMemo(() => ({
    deal,
    notes,
    cost,
    roi,
    currency: tweak.currency,
    markupLow: tweak.markupLow,
    markupHigh: tweak.markupHigh,
    shareLow: tweak.shareLow,
    shareHigh: tweak.shareHigh,
    quadrants: quadrants.map((q) => ({ m: q.m, s: q.s, rec: q.rec })),
    bandMin: band.min,
    bandMax: band.max,
    finalPrice: finalPrice ?? 0,
    margin: finalPrice && finalPrice > 0 ? (finalPrice - cost) / finalPrice : 0,
    captured: roi > 0 ? (finalPrice ?? 0) / roi : 0,
  }), [deal, notes, cost, roi, tweak.currency, tweak.markupLow, tweak.markupHigh, tweak.shareLow, tweak.shareHigh, quadrants, band.min, band.max, finalPrice]);

  const handleAiToggle = () => {
    setAiOpen((open) => {
      const next = !open;
      if (next) {
        setAiPulse(true);
        setTimeout(() => setAiPulse(false), 1200);
      }
      return next;
    });
  };

  const handleAiApplyPrice = (price) => {
    setFinalPrice(price);
    setAiPulse(true);
    setTimeout(() => setAiPulse(false), 1200);
  };

  // pick selected quadrant's recommendation as default final price
  useEffect(() => {
    const sel = quadrants.find((q) => q.m === selected.m && q.s === selected.s);
    if (sel) setFinalPrice(sel.rec);
  }, [selected.m, selected.s, cost, roi]);

  // Sensitivity grid: spread around the chosen presets
  const sensMarkups = [
    +(tweak.markupLow - 0.05).toFixed(2),
    tweak.markupLow,
    tweak.markupHigh,
    +(tweak.markupHigh + 0.05).toFixed(2),
  ];
  const sensShares = [
    +(tweak.shareLow - 0.05).toFixed(2),
    tweak.shareLow,
    tweak.shareHigh,
    +(tweak.shareHigh + 0.05).toFixed(2),
  ].filter((v) => v > 0);

  const copySummary = async () => {
    const lines = [
      `${t.sumDeal}: ${deal}`,
      `${t.sumCost}: ${fmtMoney(cost, tweak.currency, tweak.decimals)}`,
      `${t.sumRoi}: ${fmtMoney(roi, tweak.currency, tweak.decimals)}`,
      `${t.sumPrice}: ${fmtMoney(finalPrice, tweak.currency, tweak.decimals)}`,
      `  • ${t.floor} (×${tweak.markupLow}, ${(tweak.shareLow * 100).toFixed(0)}%): ${fmtMoney(band.min, tweak.currency, tweak.decimals)}`,
      `  • ${t.ceiling} (×${tweak.markupHigh}, ${(tweak.shareHigh * 100).toFixed(0)}%): ${fmtMoney(band.max, tweak.currency, tweak.decimals)}`,
      `${t.sumNotes}: ${notes}`,
    ];
    try {
      await navigator.clipboard.writeText(lines.join('\n'));
    } catch {}
  };

  return (
    <div className="app">
      <header className="topbar">
        <div className="brand">
          <img src="assets/logo.png" alt="Dialoga" className="brand-logo" />
          <div className="brand-divider" aria-hidden="true" />
          <div>
            <div className="brand-name">Pricing Studio</div>
            <div className="brand-sub">{t.brandSub}</div>
          </div>
        </div>
        <div className="topbar-right">
          <div className="lang-toggle" role="tablist" aria-label="Language">
            <button
              type="button"
              role="tab"
              aria-selected={tweak.lang === 'en'}
              className={`lang-opt ${tweak.lang === 'en' ? 'is-on' : ''}`}
              onClick={() => setTweak('lang', 'en')}
            >
              <span className="lang-flag" aria-hidden="true">EN</span>
              <span className="lang-name">English</span>
            </button>
            <button
              type="button"
              role="tab"
              aria-selected={tweak.lang === 'es'}
              className={`lang-opt ${tweak.lang === 'es' ? 'is-on' : ''}`}
              onClick={() => setTweak('lang', 'es')}
            >
              <span className="lang-flag" aria-hidden="true">ES</span>
              <span className="lang-name">Español</span>
            </button>
          </div>
          <div className="topbar-meta mono">
            <span>v1.0</span>
            <span className="dot" />
            <span>{new Date().toLocaleDateString(tweak.lang === 'es' ? 'es-ES' : 'en-US', { month: 'short', day: 'numeric', year: 'numeric' })}</span>
          </div>
        </div>
      </header>

      <main className="grid">
        {/* LEFT — Inputs */}
        <section className="panel inputs">
          <div className="panel-head">
            <div className="panel-eyebrow">{t.inputsEyebrow}</div>
            <h2 className="panel-title">{t.inputsTitle}</h2>
          </div>

          <div className="field">
            <label>{t.dealName}</label>
            <input type="text" className="text-input" value={deal} onChange={(e) => setDeal(e.target.value)} placeholder={t.dealPh} />
          </div>

          <div className="field">
            <label>{t.operativeCost} <span className="hint">{t.operativeHint}</span></label>
            <MoneyInput value={cost} onChange={setCost} prefix="$" />
          </div>

          <div className="field">
            <label>{t.roiLabel} <span className="hint">{t.roiHint}</span></label>
            <MoneyInput value={roi} onChange={setRoi} prefix="$" />
          </div>

          <div className="field">
            <label>{t.notes}</label>
            <textarea className="text-input" rows={4} value={notes} onChange={(e) => setNotes(e.target.value)} />
          </div>

          <div className="formula">
            <div className="formula-head">{t.formulasHead}</div>
            <div className="formula-row mono">
              <span className="formula-name">{t.floor}</span>
              <span className="formula-eq">{t.floorEq}</span>
            </div>
            <div className="formula-row mono">
              <span className="formula-name">{t.ceiling}</span>
              <span className="formula-eq">{t.ceilingEq}</span>
            </div>
            <div className="formula-row mono accent">
              <span className="formula-name">{t.price}</span>
              <span className="formula-eq">{t.priceEq}</span>
            </div>
          </div>

          <div className="actions">
            <button type="button" className="btn ghost" onClick={() => { setCost(0); setRoi(0); setNotes(''); setDeal(''); setFinalPrice(null); if (onReset) onReset(); }}>{t.reset}</button>
            <button type="button" className="btn primary" onClick={copySummary}>{t.copy}</button>
          </div>
        </section>

        {/* RIGHT — Decision */}
        <section className="panel decision">
          <div className="panel-head row">
            <div>
              <div className="panel-eyebrow">{t.decisionEyebrow}</div>
              <h2 className="panel-title">{t.decisionTitle}</h2>
            </div>
            <div className="band-readout">
              <div className="band-readout-label">{t.band}</div>
              <div className="band-readout-value mono">
                {fmtMoney(band.min, tweak.currency, tweak.decimals)} → {fmtMoney(band.max, tweak.currency, tweak.decimals)}
              </div>
            </div>
          </div>

          <div className="quad-grid">
            {quadrants.map((q) => (
              <QuadrantCard
                key={`${q.m}-${q.s}`}
                markup={q.m}
                share={q.s}
                cost={cost}
                roi={roi}
                currency={tweak.currency}
                decimals={tweak.decimals}
                selected={selected.m === q.m && selected.s === q.s}
                onSelect={() => setSelected({ m: q.m, s: q.s })}
                t={t}
              />
            ))}
          </div>

          <div className="panel-head">
            <div className="panel-eyebrow">{t.commitEyebrow}</div>
            <h2 className="panel-title">{t.commitTitle}</h2>
          </div>

          <div className="decider-wrap">
            <DecisionSlider
              min={band.min}
              max={band.max}
              value={finalPrice ?? band.min}
              onChange={setFinalPrice}
              currency={tweak.currency}
              decimals={tweak.decimals}
              t={t}
              pulse={aiPulse}
            />
          </div>

          <Verdict price={finalPrice ?? 0} cost={cost} roi={roi} t={t} />

          {tweak.showSensitivity && (
            <Sensitivity
              cost={cost}
              roi={roi}
              markups={sensMarkups}
              shares={sensShares}
              currency={tweak.currency}
              decimals={tweak.decimals}
              finalPrice={finalPrice ?? 0}
              onPick={(v) => setFinalPrice(v)}
              t={t}
            />
          )}
        </section>
      </main>


      {/* ── FIX 4: Estimation audit panel ── */}
      {(window._estimateCostBreakdown || window._estimateRoiBreakdown) && (
        <AuditPanel
          costBreakdown={window._estimateCostBreakdown || ''}
          roiBreakdown={window._estimateRoiBreakdown || ''}
          cost={cost}
          roi={roi}
          lang={tweak.lang}
        />
      )}

      {/* ── Phase 04: Report Generator ── */}
      {window.ReportGenerator && finalPrice && (
        <div className="rpt-wrapper">
          <window.ReportGenerator
            lang={tweak.lang}
            ctx={{
              deal,
              notes,
              cost,
              roi,
              currency: tweak.currency,
              bandMin: band.min,
              bandMax: band.max,
              finalPrice: finalPrice ?? 0,
              margin: (finalPrice && finalPrice > 0) ? (finalPrice - cost) / finalPrice : 0,
              captured: roi > 0 ? (finalPrice ?? 0) / roi : 0,
              costBreakdown: window._estimateCostBreakdown || '',
              roiBreakdown: window._estimateRoiBreakdown || '',
            }}
          />
        </div>
      )}

      {/* ── FIX 1: Persistent estimator chat as floating panel ── */}
      {window.Estimator && (
        <EstimatorDrawer
          lang={tweak.lang}
          modelSelection={modelSelection}
          onApplyEstimate={({ deal: d, cost: c, roi: r, costBreakdown, roiBreakdown }) => {
            if (c) setCost(c);
            if (r) setRoi(r);
            if (d) setDeal(d);
            if (costBreakdown) window._estimateCostBreakdown = costBreakdown;
            if (roiBreakdown) window._estimateRoiBreakdown = roiBreakdown;
          }}
        />
      )}

      {window.TweaksPanel && (
        <window.TweaksPanel title="Tweaks">
          <window.TweakSection title="Markup presets">
            <window.TweakSlider label="Low markup" min={1.05} max={1.50} step={0.01} value={tweak.markupLow} onChange={(v) => setTweak('markupLow', v)} format={(v) => `×${v.toFixed(2)}`} />
            <window.TweakSlider label="High markup" min={1.05} max={1.50} step={0.01} value={tweak.markupHigh} onChange={(v) => setTweak('markupHigh', v)} format={(v) => `×${v.toFixed(2)}`} />
          </window.TweakSection>
          <window.TweakSection title="ROI share presets">
            <window.TweakSlider label="Low share" min={0.05} max={0.40} step={0.01} value={tweak.shareLow} onChange={(v) => setTweak('shareLow', v)} format={(v) => `${(v * 100).toFixed(0)}%`} />
            <window.TweakSlider label="High share" min={0.05} max={0.40} step={0.01} value={tweak.shareHigh} onChange={(v) => setTweak('shareHigh', v)} format={(v) => `${(v * 100).toFixed(0)}%`} />
          </window.TweakSection>
          <window.TweakSection title="Display">
            <window.TweakSelect label="Currency" value={tweak.currency} onChange={(v) => setTweak('currency', v)} options={[
              { value: 'USD', label: 'USD ($)' },
              { value: 'EUR', label: 'EUR (€)' },
              { value: 'MXN', label: 'MXN ($)' },
              { value: 'COP', label: 'COP ($)' },
              { value: 'ARS', label: 'ARS ($)' },
              { value: 'GBP', label: 'GBP (£)' },
            ]} />
            <window.TweakRadio label="Decimals" value={tweak.decimals} onChange={(v) => setTweak('decimals', v)} options={[
              { value: 0, label: '0' },
              { value: 2, label: '2' },
            ]} />
            <window.TweakToggle label="Sensitivity grid" value={tweak.showSensitivity} onChange={(v) => setTweak('showSensitivity', v)} />
          </window.TweakSection>
        </window.TweaksPanel>
      )}
    </div>
  );
}

// ── Root — handles phase switching between Estimator and Calculator ──────
function Root() {
  const [phase, setPhase] = React.useState('estimate'); // 'estimate' | 'calculate'
  const [prefill, setPrefill] = React.useState(null);
  const [lang, setLang] = React.useState('en');
  const [modelSelection, setModelSelection] = React.useState('standard');

  // ── AUTH STATE ──
  const [authState, setAuthState] = React.useState('checking'); // 'checking' | 'in' | 'out'
  const [authUser, setAuthUser] = React.useState(null);

  React.useEffect(() => {
    fetch('/api/auth/me')
      .then(r => r.json())
      .then(data => {
        if (data.authenticated) {
          setAuthUser(data.user);
          setAuthState('in');
        } else {
          setAuthState('out');
        }
      })
      .catch(() => setAuthState('out'));
  }, []);

  const handleEstimateApply = ({ deal, cost, roi, costBreakdown, roiBreakdown }) => {
    if (costBreakdown) window._estimateCostBreakdown = costBreakdown;
    if (roiBreakdown) window._estimateRoiBreakdown = roiBreakdown;
    setPrefill({ deal, cost, roi });
    setPhase('calculate');
    setTimeout(() => {
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }, 100);
  };

  const handleReset = () => {
    setPrefill(null);
    setPhase('estimate');
    window._estimateCostBreakdown = '';
    window._estimateRoiBreakdown = '';
  };

  // ── AUTH GATE — runs before anything else renders ──
  if (authState === 'checking') {
    return (
      <div className="app" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '70vh' }}>
        <div className="est-thinking" style={{ display: 'inline-flex', gap: '6px' }}>
          <span className="est-dot" /><span className="est-dot" /><span className="est-dot" />
        </div>
      </div>
    );
  }

  if (authState === 'out') {
    // Read any auth_error from the URL to show a helpful message
    const params = new URLSearchParams(window.location.search);
    const err = params.get('auth_error');
    const errMsg = err === 'domain_not_allowed'
      ? 'Access is restricted to @d1aloga.com accounts.'
      : err ? 'Sign-in failed. Please try again.' : null;

    return (
      <div className="app">
        <header className="topbar">
          <div className="brand">
            <img src="assets/logo.png" alt="Dialoga" className="brand-logo" />
            <div className="brand-divider" aria-hidden="true" />
            <div>
              <div className="brand-name">Pricing Studio</div>
              <div className="brand-sub">DiALOGA internal tool</div>
            </div>
          </div>
        </header>
        <main style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '60vh' }}>
          <div style={{ maxWidth: '380px', textAlign: 'center', padding: '0 24px' }}>
            <h2 className="est-phase-title" style={{ marginBottom: '8px' }}>Sign in to continue</h2>
            <p className="est-phase-sub" style={{ marginBottom: '24px' }}>
              This tool is restricted to DiALOGA team members. Sign in with your @d1aloga.com account.
            </p>
            {errMsg && (
              <div style={{ fontSize: '13px', color: 'var(--red, #DC2626)', padding: '8px 12px', background: 'rgba(220,38,38,0.07)', borderRadius: '6px', marginBottom: '16px' }}>
                {errMsg}
              </div>
            )}
            <a href="/api/auth/login" className="est-btn-primary" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', textDecoration: 'none', height: '44px', padding: '0 28px' }}>
              Sign in with Google
            </a>
          </div>
        </main>
      </div>
    );
  }

  // authState === 'in' — render the app as normal

  if (phase === 'estimate' && window.Estimator) {
    return (
      <div className="app">
        <header className="topbar">
          <div className="brand">
            <img src="assets/logo.png" alt="Dialoga" className="brand-logo" />
            <div className="brand-divider" aria-hidden="true" />
            <div>
              <div className="brand-name">Pricing Studio</div>
              <div className="brand-sub">{lang === 'es' ? 'Calculadora de ROI a 1 año' : '1st-year ROI calculator'}</div>
            </div>
          </div>
          <div className="topbar-right">
            <div className="model-toggle" style={{ marginRight: '16px', display: 'flex', gap: '4px' }}>
              <button
                type="button"
                className={`lang-opt ${modelSelection === 'standard' ? 'is-on' : ''}`}
                onClick={() => setModelSelection('standard')}
              >
                <span className="lang-name">{lang === 'es' ? 'Modo Estándar' : 'Standard Mode'}</span>
              </button>
              <button
                type="button"
                className={`lang-opt ${modelSelection === 'advanced' ? 'is-on' : ''}`}
                onClick={() => setModelSelection('advanced')}
              >
                <span className="lang-name">{lang === 'es' ? 'Modo Avanzado' : 'Advanced Mode'}</span>
              </button>
            </div>
            <div className="lang-toggle" role="tablist" aria-label="Language">
              <button type="button" role="tab" aria-selected={lang === 'en'} className={`lang-opt ${lang === 'en' ? 'is-on' : ''}`} onClick={() => setLang('en')}>
                <span className="lang-flag" aria-hidden="true">EN</span>
                <span className="lang-name">English</span>
              </button>
              <button type="button" role="tab" aria-selected={lang === 'es'} className={`lang-opt ${lang === 'es' ? 'is-on' : ''}`} onClick={() => setLang('es')}>
                <span className="lang-flag" aria-hidden="true">ES</span>
                <span className="lang-name">Español</span>
              </button>
            </div>
            <button
              type="button"
              className="lang-opt"
              style={{ marginLeft: '12px' }}
              onClick={() => { window.location.href = '/api/auth/logout'; }}
              title={authUser?.email || ''}
            >
              <span className="lang-name">{lang === 'es' ? 'Salir' : 'Sign out'}</span>
            </button>
          </div>
        </header>
        <main className="est-fullwidth-main">
            <window.Estimator
              lang={lang}
              modelSelection={modelSelection}
              onApplyEstimate={handleEstimateApply}
              onSkip={() => setPhase('calculate')}
            />
        </main>
      </div>
    );
  }

  return <App prefill={prefill} onReset={handleReset} estimatorMessages={window._estimatorMessages || null} estimateLang={lang} modelSelection={modelSelection} />;
}


ReactDOM.createRoot(document.getElementById('root')).render(<Root />);
