// Step 3 — Strategy results
function Step3({ profile, history, onBack, onRestart, onSavePlan, user, saved }) {
  const [cppVersion, setCppVersion] = useState(0);
  const result = useMemo(() => window.buildStrategy(profile, history), [profile, history, cppVersion]);
  const [showOther, setShowOther] = useState(false);
  const horizon = profile.horizon;
  const fmt = window.fmt;
  const isEarn = result.mode === 'earn';
  const programLabel = profile.program === 'Flexible' ? 'flexible points' : profile.program + ' points';

  return (
    <div className="step-pane">
      <div className="step-header">
        <div className="step-eyebrow">Step three</div>
        <h1>Here's your <span className="accent">plan.</span></h1>
        {isEarn ? (
          <p className="lede">
            The uploaded card documents don't include sign-up bonuses, so there's nothing to churn.
            Instead, here are the cards ranked by the <strong style={{ color: 'var(--coral-deep)' }}>ongoing {programLabel}</strong> they
            earn over {horizon} months — net of annual fees.
          </p>
        ) : (
          <p className="lede">
            Based on your profile and history, here's a sequence designed to maximise{' '}
            <strong style={{ color: 'var(--coral-deep)' }}>{programLabel}</strong> over the next {horizon} months — net of annual fees.
          </p>
        )}
      </div>

      {/* Headline stats */}
      {isEarn ? (
        <div className="headline-stats">
          <div className="stat mint">
            <div className="stat-label">Best card net value</div>
            <div className="stat-value">{fmt.money(result.totals.net)}<span className="stat-suffix">/{horizon}mo</span></div>
          </div>
          <div className="stat accent">
            <div className="stat-label">Points earned</div>
            <div className="stat-value">{fmt.points(result.totals.ongoingPoints / 1000)}<span className="stat-suffix">k</span></div>
          </div>
          <div className="stat">
            <div className="stat-label">Fees ({horizon}mo)</div>
            <div className="stat-value">{fmt.money(result.totals.fees)}</div>
          </div>
          <div className="stat">
            <div className="stat-label">Cards compared</div>
            <div className="stat-value">{result.plan.length}</div>
          </div>
        </div>
      ) : (
        <div className="headline-stats">
          <div className="stat accent">
            <div className="stat-label">Bonus points</div>
            <div className="stat-value">{fmt.points(result.totals.bonusPoints / 1000)}<span className="stat-suffix">k</span></div>
          </div>
          <div className="stat mint">
            <div className="stat-label">
              Net earnings
              <InfoTip text={'Based on estimated point values for Qantas, Velocity and other rewards programs. Actual redemption value will depend on how and when points are used. You can set custom point values within the “How we calculate ongoing earn” tab.'} />
            </div>
            <div className="stat-value">{fmt.money(result.totals.netEarnings)}</div>
          </div>
          <div className="stat">
            <div className="stat-label">Total fees</div>
            <div className="stat-value">{fmt.money(result.totals.fees)}</div>
          </div>
          <div className="stat">
            <div className="stat-label">Cards in plan</div>
            <div className="stat-value">{result.totals.cards}</div>
          </div>
        </div>
      )}

      <MethodPanel isEarn={isEarn} horizon={horizon} onCppChange={() => setCppVersion(v => v + 1)} />

      {/* Timeline — bonus mode only */}
      {!isEarn && result.plan.length > 0 && <Timeline plan={result.plan} horizon={horizon} />}

      {/* Held cards */}
      {result.held.length > 0 && (
        <>
          <div className="section-title">
            <h2>You already have these</h2>
            <span className="pill">Ongoing earn</span>
          </div>
          {result.held.map(h => (
            <div className="held-card" key={h.card.id}>
              <IssuerSwatch issuer={h.card.issuer} />
              <div>
                <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700 }}>{h.card.name}</div>
                <div style={{ color: 'var(--ink-dim)', fontSize: '0.88rem', marginTop: 4 }}>
                  {h.card.currency} · {h.card.earnRate} pt/$ · blocks {h.card.groupLabel} bonuses while held
                </div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div className="tag mint">~{fmt.money(h.ongoingValuePerYear)}/yr earn</div>
              </div>
            </div>
          ))}
        </>
      )}

      {/* Recommended / ranked cards */}
      {result.plan.length > 0 ? (
        <>
          <div className="section-title">
            <h2>{isEarn ? 'Ranked for you' : 'Apply in this order'}</h2>
            <span className="pill">{isEarn ? 'By ongoing value' : 'Sorted by net value'}</span>
          </div>
          {isEarn
            ? result.plan.map((item, i) => (
                <EarnResultCard key={item.card.id} item={item} rank={i + 1} profile={profile} horizon={horizon} isBest={result.best && result.best.card.id === item.card.id} />
              ))
            : result.plan.map((item, i) => (
                <ResultCard key={item.card.id} item={item} rank={i + 1} profile={profile} />
              ))}
        </>
      ) : (
        <div className="empty-results">
          <h3>Nothing to recommend.</h3>
          <p>No cards in the documents match your program preference. Try the "Flexible" option in step 1.</p>
        </div>
      )}

      {/* Other programs / not available */}
      {result.notAvailable.length > 0 && (
        <div className="ineligible-section">
          <button className={'collapse-toggle ' + (showOther ? 'open' : '')} onClick={() => setShowOther(!showOther)}>
            <span>{isEarn ? 'Other programs' : 'Not yet available'} · {result.notAvailable.length} card{result.notAvailable.length === 1 ? '' : 's'}</span>
            <span className="chev">▾</span>
          </button>
          {showOther && result.notAvailable.map(item => (
            <div className="ineligible-card" key={item.card.id}>
              <div className="ic-swatch" style={{ background: `linear-gradient(135deg, ${window.ISSUER_TONES[item.card.issuer]?.bg}, ${window.ISSUER_TONES[item.card.issuer]?.dot})` }} />
              <div className="ic-name">{item.card.name}</div>
              <div className="ic-reason">{item.reason}</div>
            </div>
          ))}
        </div>
      )}

      <div className="btn-row">
        <button className="btn btn-ghost" onClick={onBack}>← Back to history</button>
        <button className="btn btn-soft" onClick={onRestart}>↻ Recalculate</button>
      </div>

      {/* Save-to-account CTA */}
      {!saved ? (
        <div className="save-cta">
          <div className="save-cta-text">
            <h3>Save this plan to your free account</h3>
            <p>Keep your card history and plan in one place — and get a fresh plan whenever offers change.</p>
          </div>
          <button className="btn btn-primary" onClick={() => onSavePlan && onSavePlan(result)}>
            {user ? 'Save to my account' : 'Save this plan →'}
          </button>
        </div>
      ) : (
        <div className="save-cta saved">
          <div className="save-cta-text">
            <h3>✓ Plan saved to your account</h3>
            <p>Find it any time on your dashboard.</p>
          </div>
        </div>
      )}

      <div className="disclaimer">
        Card data sourced only from the documents provided. Point values (cpp) are assumptions, not from those documents.
        This tool provides general information only and is not financial advice. Always check current card terms before applying.
      </div>
    </div>
  );
}

/* ─── Earn-mode result card ────────────────────────────────── */
function EarnResultCard({ item, rank, profile, horizon, isBest }) {
  const { card, nv } = item;
  const fmt = window.fmt;
  const cpp = window.CPP[card.program];

  return (
    <div className="result-card" style={isBest ? { boxShadow: '6px 6px 0 0 var(--ink-900)', borderColor: 'var(--ink-900)' } : null}>
      <div className="rc-header">
        <IssuerBadge issuer={card.issuer} name={card.name} />
        <div>
          <div className="rc-name">
            {card.name}
            {isBest && <span className="tag mint" style={{ marginLeft: 10, verticalAlign: 'middle' }}>Best value</span>}
          </div>
          <div className="rc-sub">
            <span>{card.issuer}</span>
            <span className="dot">{card.currency}</span>
          </div>
        </div>
        <div className="rc-rank">
          <span className="rank-num">#{rank}</span>
          rank
        </div>
      </div>

      <div className="rc-body">
        <div className="rc-stat">
          <div className="rc-stat-label">Earn rate</div>
          <div className={'rc-stat-value ' + (item.earnUnknown ? 'amber' : 'coral')}>
            {item.earnUnknown ? 'Not in docs' : `${card.earnRate} pt/$`}
          </div>
        </div>
        <div className="rc-stat">
          <div className="rc-stat-label">Annual fee</div>
          <div className={'rc-stat-value ' + (item.feeUnknown ? 'amber' : '')}>
            {item.feeUnknown ? 'Not in docs' : fmt.money(card.annualFee)}
          </div>
        </div>
        <div className="rc-stat">
          <div className="rc-stat-label">Points / {horizon}mo</div>
          <div className="rc-stat-value mint">{item.earnUnknown ? '—' : fmt.points(nv.ongoingPoints)}</div>
        </div>
        <div className="rc-stat">
          <div className="rc-stat-label">Net value / {horizon}mo</div>
          <div className={'rc-stat-value ' + (nv.net < 0 ? '' : 'mint')}>
            {item.earnUnknown ? '—' : fmt.money(nv.net)}
          </div>
        </div>
      </div>

      <div className="rc-active-note">
        {card.earnNote}
      </div>

      {(card.annualFeeNote || item.earnUnknown) && (
        <div className="warning" style={{ background: 'var(--cream-2)', borderColor: 'var(--line-strong)', color: 'var(--ink-dim)', margin: '0 26px 16px' }}>
          <span>ℹ️</span>
          <span>
            {card.annualFeeNote ? card.annualFeeNote + '. ' : ''}
            {item.earnUnknown ? 'Earn rate isn\'t stated in the provided documents, so this card can\'t be valued — only its fee is shown.' : ''}
          </span>
        </div>
      )}

      <div className="rc-breakdown">
        {item.earnUnknown ? (
          <span>Can't compute value — earn rate not in source documents.</span>
        ) : (
          <>
            <span>
              {fmt.points(nv.ongoingPoints)} pts × {cpp}c = <strong>{fmt.money(nv.ongoingValue)}</strong>
            </span>
            <span>− fee {fmt.money(nv.feeForHorizon)} ({horizon}mo)</span>
            <span className={'net ' + (nv.net < 0 ? 'negative' : '')}>= net {fmt.money(nv.net)}</span>
          </>
        )}
        <span style={{ marginLeft: 'auto', opacity: 0.6, fontSize: '0.78rem' }}>src: {card.source}</span>
      </div>
    </div>
  );
}

/* ─── Timeline (bonus mode) ────────────────────────────────── */
function Timeline({ plan, horizon }) {
  const cols = horizon;
  const monthLabels = [];
  for (let i = 1; i <= cols; i++) monthLabels.push(i);
  return (
    <div className="timeline">
      <div className="timeline-header">
        <div className="timeline-title">Your {horizon}-month plan</div>
        <div className="timeline-legend">
          <span><span className="legend-dot" style={{ background: 'var(--yellow)' }} />Apply</span>
          <span><span className="legend-dot" style={{ background: 'var(--amber)' }} />Hit min spend</span>
          <span><span className="legend-dot" style={{ background: 'var(--mint)' }} />🎯 Bonus lands</span>
          <span><span className="legend-dot" style={{ background: 'var(--ink-600)', border: '1px dashed rgba(255,255,255,0.3)' }} />✕ Cancel</span>
        </div>
      </div>
      <div className="timeline-grid">
        <div className="tl-months">
          <div />
          <div className="tl-month-row" style={{ '--months': cols }}>
            {monthLabels.map(m => <span key={m}>M{m}</span>)}
          </div>
        </div>
        {plan.map((item) => (
          <div className="tl-row" key={item.card.id}>
            <div className="tl-label" title={item.card.name}>{shortName(item.card.name)}</div>
            <div className="tl-track" style={{ '--months': cols }}>
              {monthLabels.map(m => <div className="tick" key={m} />)}
              {renderBars(item, cols)}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function renderBars(item, cols) {
  const { applyAt, bonusLandsAt, cancelAt, card } = item;
  const spendEnd = Math.min(bonusLandsAt, cols);
  const bonusEnd = Math.min(cols, bonusLandsAt + 1);
  const bars = [];
  if (applyAt < cols) bars.push(<div key="apply" className="tl-bar apply" style={{ ...spanCols(applyAt, applyAt + 1, cols), zIndex: 3 }}>Apply</div>);
  if (spendEnd > applyAt) bars.push(<div key="spend" className="tl-bar spend" style={{ ...spanCols(applyAt, spendEnd, cols), top: 14, height: 14, fontSize: '0.65rem', zIndex: 2 }}>${(card.minSpend / 1000).toFixed(0)}k spend</div>);
  if (bonusLandsAt < cols) {
    const firstTranche = (card.bonusTranches || []).find(t => !t.conditional);
    const k = firstTranche ? Math.round(firstTranche.points / 1000) : '';
    bars.push(<div key="bonus" className="tl-bar bonus" style={{ ...spanCols(bonusLandsAt, bonusEnd, cols), zIndex: 3 }} title={firstTranche ? firstTranche.label : 'Bonus lands'}>🎯{k}k</div>);
  }
  if (cancelAt < cols) {
    const pos = Math.min(cancelAt, cols - 1);
    bars.push(<div key="cancel" className="tl-bar cancel" style={{ ...spanCols(pos, pos + 1, cols), zIndex: 4 }} title="Cancel card — first bonus received, only Y1 fee paid">✕</div>);
  }
  // Anniversary tranches are forfeited (card cancelled after first bonus) — show
  // them faded with a strike so the user sees what they're giving up.
  (card.bonusTranches || []).forEach((t, idx) => {
    if (idx === 0) return;
    const at = applyAt + t.monthOffset;
    if (at < cols) bars.push(<div key={'tr' + idx} className="tl-bar" style={{ ...spanCols(at, Math.min(cols, at + 1), cols), background: 'rgba(255,255,255,0.06)', color: 'rgba(255,255,255,0.4)', fontSize: '0.62rem', textDecoration: 'line-through', border: '1px dashed rgba(255,255,255,0.18)', zIndex: 2 }} title={'Forfeited — ' + t.label}>{Math.round(t.points / 1000)}k</div>);
  });
  return bars;
}

function spanCols(startCol, endCol, totalCols) {
  return { position: 'absolute', left: (startCol / totalCols) * 100 + '%', width: ((endCol - startCol) / totalCols) * 100 + '%' };
}

function shortName(name) {
  return name.replace(' Credit Card', '').replace(' Mastercard', '').replace('CommBank ', '').replace(' Platinum', ' Plat').replace(' Signature', ' Sig');
}

/* ─── Single result card (bonus mode) ──────────────────────── */
function ResultCard({ item, rank, profile }) {
  const { card, applyAt, nv } = item;
  const fmt = window.fmt;
  const cpp = window.cppForCurrency(card.currency);
  const tight = item.minSpendTight;
  const applyLabel = applyAt === 0 ? 'Apply now' : `Apply in month ${applyAt + 1}`;

  return (
    <div className="result-card">
      <div className="rc-header">
        <IssuerBadge issuer={card.issuer} name={card.name} />
        <div>
          <div className="rc-name">
            {card.name}
            {item.amexFirst && <span className="tag coral" style={{ marginLeft: 10, verticalAlign: 'middle' }}>Apply first</span>}
          </div>
          <div className="rc-sub">
            <span>{card.issuer}</span>
            <span className="dot">{card.currency}</span>
            {profile.program === 'Velocity' && card.program !== 'Velocity' && (
              <span className="dot" style={{ color: 'var(--purple)', fontWeight: 600 }}>→ transfers to Velocity</span>
            )}
            <span className="dot">{card.earnNote}</span>
          </div>
        </div>
        <div className="rc-rank"><span className="rank-num">#{rank}</span>rank</div>
      </div>
      <div className="rc-body">
        <div className="rc-stat"><div className="rc-stat-label">When</div><div className="rc-stat-value coral">{applyLabel}</div></div>
        <div className="rc-stat"><div className="rc-stat-label">Bonus points</div><div className="rc-stat-value mint">{fmt.points(nv.bonusPoints)}</div></div>
        <div className="rc-stat"><div className="rc-stat-label">Min spend</div><div className={'rc-stat-value ' + (tight ? 'amber' : '')}>{fmt.money(card.minSpend)} / {card.minSpendMonths}mo</div></div>
        <div className="rc-stat"><div className="rc-stat-label">Annual fee (Y1)</div><div className="rc-stat-value">{fmt.money(card.annualFeeY1)}</div></div>
      </div>
      <div className="rc-active-note">
        <span className="tag coral">Active card</span>&nbsp;Months {item.activeStart + 1}–{item.activeEnd} ({item.activeMonths}mo of spend) · {card.groupLabel} · {card.exclusionUnverified ? 'exclusion unverified' : card.exclusionMonths + 'mo exclusion'}
        {item.gatedByExclusion && (
          <span style={{ width: '100%', marginTop: 6, color: 'var(--orange-deep)' }}>
            ↳ Can't apply until month {applyAt + 1} — earliest the {card.groupLabel} exclusion clock clears.
          </span>
        )}
      </div>
      {card.bonusTranches.length > 1 && (
        <div className="rc-tranches">
          {card.bonusTranches.map((t, i) => (
            <div key={i} className={'tranche ' + (i > 0 || t.conditional ? 'conditional' : '')} title={i > 0 ? 'Forfeited — card cancelled after the first bonus' : ''}>
              <strong>{fmt.points(t.points)}</strong> · {t.label}{i > 0 ? ' — forfeited' : ''}
            </div>
          ))}
        </div>
      )}
      {tight && (
        <div className="warning"><span>⚠️</span><span>Tight minimum spend — needs {fmt.money(card.minSpend / card.minSpendMonths)}/mo (you have {fmt.money(profile.monthlySpend)}/mo).</span></div>
      )}
      <div className="rc-breakdown">
        <span>{fmt.points(nv.bonusPoints)} pts × {cpp}c = <strong>{fmt.money(nv.bonusValue)}</strong></span>
        {nv.cashback > 0 && <span>+ {fmt.money(nv.cashback)} cashback</span>}
        {nv.ongoingValue > 0 && <span>+ {fmt.money(nv.ongoingValue)} ongoing</span>}
        <span>− fee {fmt.money(nv.annualFee)}</span>
        <span className={'net ' + (nv.net < 0 ? 'negative' : '')}>= net {fmt.money(nv.net)}</span>
      </div>
    </div>
  );
}

window.Step3 = Step3;

/* ─── Info tooltip ─────────────────────────────────────────── */
function InfoTip({ text }) {
  return (
    <span className="infotip" tabIndex={0} role="img" aria-label="More info">
      <span className="infotip-icon">i</span>
      <span className="infotip-bubble">{text}</span>
    </span>
  );
}

/* ─── Method panel — tabbed explainer + point-value editor ──── */
function MethodPanel({ isEarn, horizon, onCppChange }) {
  const [open, setOpen] = useState(false);
  const [tab, setTab] = useState('how');

  return (
    <div className={'method-note panel ' + (open ? 'open' : '')}>
      <button className="panel-summary" onClick={() => setOpen(o => !o)} aria-expanded={open}>
        <span>How we calculate ongoing earn</span>
        <span className="panel-chev">{open ? '−' : '+'}</span>
      </button>

      {open && (
        <div className="panel-body">
          <div className="panel-tabs">
            <button className={'panel-tab ' + (tab === 'how' ? 'active' : '')} onClick={() => setTab('how')}>How we calculate</button>
            <button className={'panel-tab ' + (tab === 'values' ? 'active' : '')} onClick={() => setTab('values')}>Set your own point values</button>
          </div>

          {tab === 'how' ? (
            <div className="method-body">
              <p style={{ marginTop: 0 }}>
                Your monthly spend can only run through <strong>one card at a time</strong>. Each card earns ongoing
                points only during its <em>active window</em>.
              </p>
              <ul>
                <li>Active window for card N = <code>applyAt[N]</code> until <code>applyAt[N+1]</code> (or horizon / month 12)</li>
                <li>Ongoing points = <code>monthlySpend × earnRate × activeMonths</code></li>
                <li>We assume you <strong>cancel each card as soon as its first bonus lands</strong> — you pay only the first-year fee, the issuer-group exclusion clock starts immediately, and any anniversary/retention tranches are forfeited</li>
                <li><strong>Net earnings</strong> = dollar value of all points earned (sign-up bonus + ongoing spend, at each program's point value) <strong>minus total annual fees</strong></li>
                <li>Point values are estimates — set your own in the next tab.</li>
              </ul>
            </div>
          ) : (
            <PointValuesForm onCppChange={onCppChange} />
          )}
        </div>
      )}
    </div>
  );
}

/* ─── Point-value editor ───────────────────────────────────── */
function PointValuesForm({ onCppChange }) {
  const fields = [
    { key: 'qantas', label: 'Qantas Points' },
    { key: 'velocity', label: 'Velocity Points' },
    { key: 'amex', label: 'AMEX Membership Rewards' },
    { key: 'bank', label: 'Bank rewards points', hint: 'e.g. CommBank Awards, ANZ Rewards' },
    { key: 'giftcard', label: 'Gift card redemptions' },
  ];
  const [vals, setVals] = useState(() => window.getCustomCpp());
  const [savedFlag, setSavedFlag] = useState(false);

  function update(key, raw) {
    const num = raw === '' ? '' : parseFloat(raw);
    setVals(v => ({ ...v, [key]: num }));
    setSavedFlag(false);
  }
  function apply() {
    const clean = {};
    fields.forEach(f => {
      const n = parseFloat(vals[f.key]);
      clean[f.key] = isNaN(n) || n < 0 ? window.CPP_DEFAULTS[f.key] : n;
    });
    setVals(clean);
    window.setCustomCpp(clean);
    setSavedFlag(true);
    onCppChange && onCppChange();
  }
  function reset() {
    window.resetCustomCpp();
    setVals(window.getCustomCpp());
    setSavedFlag(false);
    onCppChange && onCppChange();
  }

  return (
    <div className="method-body">
      <p style={{ marginTop: 0 }}>
        Enter your own value (in cents) for each point. These drive the dollar figures across your plan —
        bank points are valued at the higher of your bank-rewards and gift-card rates.
      </p>
      <div className="cpp-grid">
        {fields.map(f => (
          <div className="cpp-field" key={f.key}>
            <label>
              {f.label}
              {f.hint && <span className="cpp-hint">{f.hint}</span>}
            </label>
            <div className="cpp-input">
              <input type="number" min="0" step="0.05" value={vals[f.key]}
                onChange={(e) => update(f.key, e.target.value)} />
              <span className="cpp-unit">c / pt</span>
            </div>
          </div>
        ))}
      </div>
      <div className="cpp-actions">
        <button className="btn btn-primary" style={{ padding: '11px 22px', fontSize: '0.92rem' }} onClick={apply}>
          {savedFlag ? '✓ Applied' : 'Apply values'}
        </button>
        <button className="link-btn" onClick={reset}>Reset to defaults</button>
      </div>
    </div>
  );
}
