// screens.jsx — Mortgage app: Dashboard, Calculator, Charts, Learn.
// Uses MortgageEngine, LineChart, InputsPanel globals.

const { useMemo: useMemoScr, useState: useStateScr, useEffect: useEffectScr } = React;
const ME = window.MortgageEngine;

function fmt(n, mode) { return ME.fmtGBP(n, mode); }

function AnimatedNumber({ value, format = (v) => v, duration = 700 }) {
  const [shown, setShown] = useStateScr(value);
  useEffectScr(() => {
    let raf, start = null, from = shown;
    function step(ts) {
      if (start === null) start = ts;
      const t = Math.min(1, (ts - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setShown(from + (value - from) * eased);
      if (t < 1) raf = requestAnimationFrame(step);
    }
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [value]);
  return <span>{format(shown)}</span>;
}

function StrategyCard({ title, sub, color, primaryLabel, primaryValue, rows, isBest, chipClass, fmtMode }) {
  return (
    <div className={`card strat-card ${isBest ? 'is-best' : ''}`}>
      <div className="accent-bar" style={{ background: color, boxShadow: `0 0 12px ${color}` }} />
      {isBest && <div className="best-pill">Recommended</div>}
      <span className={`chip ${chipClass}`}><span className="swatch" />{title}</span>
      <div style={{ height: 12 }} />
      <div className="label" style={{ marginBottom: 4 }}>{primaryLabel}</div>
      <div className="num num-lg" style={{ color: isBest ? color : 'var(--ink-0)' }}>
        <AnimatedNumber value={primaryValue} format={(v) => fmt(v, fmtMode)} />
      </div>
      <p style={{ color: 'var(--ink-2)', fontSize: 12, margin: '6px 0 14px', minHeight: 32 }}>{sub}</p>
      <div className="div-h" />
      {rows.map((r, i) =>
        <div key={i} className="balance-strip">
          <span style={{ fontSize: 12, color: 'var(--ink-2)' }}>{r.label}</span>
          <span className="num" style={{ fontSize: 14, color: r.muted ? 'var(--ink-2)' : 'var(--ink-0)' }}>{r.value}</span>
        </div>
      )}
    </div>
  );
}

function payoffText(sim, termYears) {
  if (sim.payoffMonth == null) return sim.type === 'interest-only' ? 'End of term (capital due)' : `End of term (yr ${termYears})`;
  if (sim.payoffMonth === 0) return 'Cleared today';
  return `Year ${(sim.payoffMonth / 12).toFixed(1)}`;
}

// ---------- DASHBOARD ----------
function DashboardScreen({ inputs, results, reco, fmtMode, chartStyle }) {
  const std = results.standard, ovr = results.overpay, lump = results.lump, inv = results.invest;
  const loan = Math.max(0, inputs.propertyPrice - inputs.deposit);
  const io = inputs.mortgageType === 'interest-only';

  const netWorth = (sim) => sim.finalInvested - sim.finalBalance;
  const wealthStd = netWorth(std), wealthOver = netWorth(ovr), wealthLump = netWorth(lump), wealthInvest = netWorth(inv);
  const bestKey = reco.best;

  // Hero chart: balance over time — overpay vs standard (the requested chart)
  const balanceSeries = [
    { key: 'standard', label: io ? 'Interest-only (flat)' : 'Standard', color: 'var(--c-std)', dashed: true,
      points: std.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'overpay', label: 'Overpay', color: 'var(--c-overpay)',
      points: ovr.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'invest', label: 'Invest (pot)', color: 'var(--c-invest)',
      points: inv.series.map((p) => ({ x: p.year, y: p.invested })) },
  ];

  return (
    <div className="stack">
      <div className="card reco card-pad-lg">
        <div className="label" style={{ color: 'var(--c-invest)', marginBottom: 18 }}>
          ● {fmt(loan, 'short')} loan · {inputs.mortgageType === 'repayment' ? 'Repayment' : 'Interest-only'} · {(inputs.fixedRate * 100).toFixed(2)}% fixed {inputs.fixedYears}y → {(inputs.revertRate * 100).toFixed(2)}% · {inputs.termYears}y term
        </div>
        <h2 className="reco-headline">
          {reco.headlinePrefix}{' '}
          <span className="reco-accent">{reco.headlineAccent}</span>{' '}
          {reco.headlineSuffix}
        </h2>
        <p style={{ maxWidth: '65ch' }}>{reco.reasoning}</p>
      </div>

      <div className="grid grid-4">
        <StrategyCard
          title="Standard" sub={io ? 'Pay only the interest; capital stays put' : 'Pay the scheduled amount, no more'}
          color="var(--c-std)" chipClass="chip-std" isBest={bestKey === 'standard'} fmtMode={fmtMode}
          primaryLabel="Net wealth at term end" primaryValue={wealthStd}
          rows={[
            { label: 'Total interest', value: fmt(std.totalInterest, fmtMode) },
            { label: 'Total paid', value: fmt(std.totalPayment, fmtMode) },
            { label: 'Balance at end', value: fmt(std.finalBalance, fmtMode), muted: std.finalBalance === 0 },
            { label: 'Mortgage-free', value: payoffText(std, inputs.termYears) },
          ]} />
        <StrategyCard
          title="Overpay" sub={`Extra £${inputs.monthlyOverpay}/mo onto the loan, then invest once it's clear`}
          color="var(--c-overpay)" chipClass="chip-overpay" isBest={bestKey === 'overpay'} fmtMode={fmtMode}
          primaryLabel="Net wealth at term end" primaryValue={wealthOver}
          rows={[
            { label: 'Interest saved', value: fmt(std.totalInterest - ovr.totalInterest, fmtMode) },
            { label: 'Mortgage-free', value: payoffText(ovr, inputs.termYears) },
            { label: 'Then invested', value: ovr.payoffMonth ? `from yr ${(ovr.payoffMonth / 12).toFixed(0)}` : '—' },
            { label: 'Portfolio at end', value: fmt(ovr.finalInvested, fmtMode) },
          ]} />
        <StrategyCard
          title="Lump sum" sub={`${fmt(inputs.lumpSum, fmtMode)} today, then the monthly ${{ invest: 'invests', overpay: 'overpays', none: 'is spent' }[inputs.lumpThenAction]}`}
          color="var(--c-lump)" chipClass="chip-lump" isBest={bestKey === 'lump'} fmtMode={fmtMode}
          primaryLabel="Net wealth at term end" primaryValue={wealthLump}
          rows={[
            { label: 'Upfront', value: fmt(inputs.lumpSum, fmtMode) },
            { label: 'Interest saved', value: fmt(std.totalInterest - lump.totalInterest, fmtMode) },
            { label: 'Then monthly', value: { invest: 'Invested', overpay: 'Overpaid', none: 'Spent' }[inputs.lumpThenAction] },
            { label: 'Mortgage-free', value: payoffText(lump, inputs.termYears) },
          ]} />
        <StrategyCard
          title="Invest" sub={`Invest £${inputs.monthlyOverpay}/mo + lump in the market instead`}
          color="var(--c-invest)" chipClass="chip-invest" isBest={bestKey === 'invest'} fmtMode={fmtMode}
          primaryLabel="Net wealth at term end" primaryValue={wealthInvest}
          rows={[
            { label: 'Portfolio value', value: fmt(inv.finalInvested, fmtMode) },
            { label: 'Real (today\u2019s £)', value: fmt(inv.series[inv.series.length - 1]?.realInvested || 0, fmtMode) },
            { label: 'Balance at end', value: fmt(inv.finalBalance, fmtMode), muted: inv.finalBalance === 0 },
            { label: 'Mortgage-free', value: payoffText(inv, inputs.termYears) },
          ]} />
      </div>

      <div className="card">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4, flexWrap: 'wrap', gap: 8 }}>
          <h3 className="card-title">Balance over time — overpay vs standard</h3>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            {balanceSeries.map((s) =>
              <span key={s.key} style={{ fontSize: 12, display: 'flex', alignItems: 'center', gap: 6, color: 'var(--ink-2)' }}>
                <span style={{ width: 10, height: 2, background: s.color, display: 'inline-block' }} />
                {s.label}
              </span>
            )}
          </div>
        </div>
        <p className="card-sub">
          {io
            ? 'On interest-only, the standard balance stays flat — only overpayments (or an investment pot) chip away at the capital.'
            : 'How fast the mortgage shrinks, and how an investment pot grows alongside it.'}
        </p>
        <LineChart series={balanceSeries} width={1000} height={340}
          style={chartStyle === 'bar' ? 'line' : chartStyle}
          xFormat={(v) => `${Math.round(v)}y`}
          yFormat={(v) => fmt(v, 'short')}
          highlightX={ovr.payoffMonth ? ovr.payoffMonth / 12 : undefined}
          highlightLabel={ovr.payoffMonth ? `Overpay clears · yr ${(ovr.payoffMonth / 12).toFixed(1)}` : null} />
      </div>
    </div>
  );
}

// ---------- CALCULATOR ----------
function CalculatorScreen({ inputs, setInputs, results, fmtMode, chartStyle }) {
  const std = results.standard, ovr = results.overpay, inv = results.invest;
  const loan = Math.max(0, inputs.propertyPrice - inputs.deposit);
  const sdlt = ME.stampDuty(inputs.propertyPrice, inputs.firstTimeBuyer);
  const netMo = ME.netMonthly(inputs.income);
  const aff = ME.affordability(inputs.income, loan, std.scheduledMonthly, netMo);
  const effRate = ME.effectiveRate(inputs);

  const balanceSeries = [
    { key: 'standard', label: 'Standard', color: 'var(--c-std)', dashed: true,
      points: std.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'overpay', label: 'Overpay', color: 'var(--c-overpay)',
      points: ovr.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'lump', label: 'Lump sum', color: 'var(--c-lump)',
      points: results.lump.series.map((p) => ({ x: p.year, y: p.balance })) },
  ];

  return (
    <div className="grid grid-calc">
      <InputsPanel inputs={inputs} setInputs={setInputs} />

      <div className="stack">
        <div className="card">
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', flexWrap: 'wrap', gap: 8 }}>
            <div>
              <h3 className="card-title">Your monthly payment</h3>
              <p className="card-sub">{inputs.mortgageType === 'repayment' ? 'Capital + interest' : 'Interest-only'} · {(inputs.fixedRate * 100).toFixed(2)}% fixed for {inputs.fixedYears}y</p>
            </div>
            <span className="chip" style={{ background: 'var(--glass-2)' }}>
              {effRate ? `${(effRate * 100).toFixed(2)}% effective` : ''}
            </span>
          </div>
          <div className="grid grid-4" style={{ marginTop: 10 }}>
            <div className="pill-stat">
              <div className="label">Monthly (fixed)</div>
              <div className="num" style={{ color: 'var(--c-overpay)' }}>{fmt(std.scheduledMonthly, 'short')}</div>
              <div className="delta">on {fmt(loan, 'short')} loan</div>
            </div>
            <div className="pill-stat">
              <div className="label">When rate reverts</div>
              <div className="num">{fmt(reversionPayment(inputs), 'short')}</div>
              <div className="delta down">at {(inputs.revertRate * 100).toFixed(2)}% SVR</div>
            </div>
            <div className="pill-stat">
              <div className="label">Total interest</div>
              <div className="num">{fmt(std.totalInterest, 'short')}</div>
              <div className="delta">over {inputs.termYears} yrs</div>
            </div>
            <div className="pill-stat">
              <div className="label">Stamp duty</div>
              <div className="num">{fmt(sdlt, 'short')}</div>
              <div className="delta">{inputs.firstTimeBuyer ? 'first-time buyer' : 'standard rate'}</div>
            </div>
          </div>
        </div>

        <div className="card">
          <h3 className="card-title">Mortgage balance — projected</h3>
          <p className="card-sub">When each strategy clears the mortgage</p>
          <LineChart series={balanceSeries} width={900} height={320}
            style={chartStyle === 'bar' ? 'area' : chartStyle}
            xFormat={(v) => `${Math.round(v)}y`}
            yFormat={(v) => fmt(v, 'short')}
            highlightX={ovr.payoffMonth ? ovr.payoffMonth / 12 : undefined}
            highlightLabel={ovr.payoffMonth ? 'Overpay clears' : null} />
        </div>

        <div className="grid grid-2">
          <div className="card">
            <h3 className="card-title">Affordability check</h3>
            <p className="card-sub">Lenders typically cap borrowing at 4.5× income</p>
            <div className="num num-xl" style={{ color: aff.withinCap ? 'var(--c-invest)' : 'var(--c-warn)', marginTop: 6 }}>
              <AnimatedNumber value={aff.multiple} format={(v) => `${v.toFixed(1)}×`} />
            </div>
            <div className="muted" style={{ fontSize: 13, marginTop: 8 }}>
              This loan is <b style={{ color: 'var(--ink-0)' }}>{aff.verdict}</b> on a {fmt(inputs.income, 'short')} income.
              Max typical borrow is {fmt(aff.maxBorrow, 'short')}. The payment is {(aff.paymentPct * 100).toFixed(0)}% of your take-home.
            </div>
          </div>
          <div className="card">
            <h3 className="card-title">Overpay vs invest, at a glance</h3>
            <p className="card-sub">£{inputs.monthlyOverpay}/mo for {inputs.termYears} years</p>
            <div className="grid grid-2" style={{ marginTop: 8 }}>
              <div className="pill-stat">
                <div className="label">Interest saved by overpaying</div>
                <div className="num" style={{ color: 'var(--c-overpay)' }}>{fmt(std.totalInterest - ovr.totalInterest, fmtMode)}</div>
                <div className="delta">guaranteed</div>
              </div>
              <div className="pill-stat">
                <div className="label">Investment pot instead</div>
                <div className="num" style={{ color: 'var(--c-invest)' }}>{fmt(inv.finalInvested, fmtMode)}</div>
                <div className="delta">{((inputs.investReturn - inputs.investFee) * 100).toFixed(2)}% / yr, at risk</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );

  function reversionPayment(inp) {
    // payment recomputed on the balance at reversion, over the remaining term
    const sim = ME.simulate({ ...baseFromInputs(inp), strategy: 'standard' });
    const idx = sim.series.find((p) => p.year >= inp.fixedYears);
    const bal = idx ? idx.balance : loan;
    return ME.scheduledPayment(bal, inp.revertRate, (inp.termYears - inp.fixedYears) * 12, inp.mortgageType);
  }
}

// shared: build engine base params from UI inputs
function baseFromInputs(inputs) {
  return {
    balance: Math.max(0, inputs.propertyPrice - inputs.deposit),
    termYears: inputs.termYears,
    mortgageType: inputs.mortgageType,
    fixedRate: inputs.fixedRate,
    fixedYears: inputs.fixedYears,
    revertRate: inputs.revertRate,
    monthlyOverpay: inputs.monthlyOverpay,
    lumpSum: inputs.lumpSum,
    lumpThenAction: inputs.lumpThenAction,
    investReturn: inputs.investReturn,
    inflation: inputs.inflation,
    investFee: inputs.investFee,
    ercAllowance: 0.10,
  };
}

// ---------- CHARTS ----------
function ChartsScreen({ inputs, results, fmtMode, chartStyle }) {
  const std = results.standard, ovr = results.overpay, inv = results.invest;

  const balanceSeries = [
    { key: 'standard', label: 'Standard', color: 'var(--c-std)', dashed: true,
      points: std.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'overpay', label: 'Overpay', color: 'var(--c-overpay)',
      points: ovr.series.map((p) => ({ x: p.year, y: p.balance })) },
    { key: 'lump', label: 'Lump', color: 'var(--c-lump)',
      points: results.lump.series.map((p) => ({ x: p.year, y: p.balance })) },
  ];

  const wealthSeries = [
    { key: 'invest', label: 'Invest', color: 'var(--c-invest)',
      points: inv.series.map((p) => ({ x: p.year, y: p.invested - p.balance })) },
    { key: 'overpay', label: 'Overpay', color: 'var(--c-overpay)',
      points: ovr.series.map((p) => ({ x: p.year, y: p.invested - p.balance })) },
    { key: 'standard', label: 'Standard', color: 'var(--c-std)', dashed: true,
      points: std.series.map((p) => ({ x: p.year, y: -p.balance })) },
  ];

  const interestSeries = [
    { key: 'std-int', label: 'Standard · interest', color: 'var(--c-std)',
      points: std.series.map((p) => ({ x: p.year, y: p.cumulativeInterest })) },
    { key: 'ovr-int', label: 'Overpay · interest', color: 'var(--c-overpay)',
      points: ovr.series.map((p) => ({ x: p.year, y: p.cumulativeInterest })) },
  ];

  let crossover = null;
  for (let i = 0; i < inv.series.length; i++) {
    const iw = inv.series[i].invested - inv.series[i].balance;
    const ow = ovr.series[i].invested - ovr.series[i].balance;
    if (iw > ow && crossover === null) { crossover = inv.series[i].year; break; }
  }

  return (
    <div className="stack">
      <div className="grid grid-2">
        <div className="card">
          <h3 className="card-title">Mortgage balance over time</h3>
          <p className="card-sub">All strategies overlaid · {inputs.termYears}-year term</p>
          <LineChart series={balanceSeries} width={680} height={300}
            style={chartStyle === 'bar' ? 'area' : chartStyle}
            xFormat={(v) => `${Math.round(v)}y`} yFormat={(v) => fmt(v, 'short')}
            highlightX={ovr.payoffMonth ? ovr.payoffMonth / 12 : undefined} highlightLabel="Overpay clears" />
        </div>
        <div className="card">
          <h3 className="card-title">Net wealth: overpay vs invest</h3>
          <p className="card-sub">Investment pot minus outstanding mortgage</p>
          <LineChart series={wealthSeries} width={680} height={300}
            style={chartStyle === 'bar' ? 'area' : chartStyle}
            xFormat={(v) => `${Math.round(v)}y`} yFormat={(v) => fmt(v, 'short')}
            highlightX={crossover || undefined}
            highlightLabel={crossover ? `Invest overtakes · yr ${crossover.toFixed(1)}` : null} />
        </div>
      </div>
      <div className="grid grid-2">
        <div className="card">
          <h3 className="card-title">Cumulative interest paid</h3>
          <p className="card-sub">Overpaying saves {fmt(std.totalInterest - ovr.totalInterest, fmtMode)} in interest</p>
          <LineChart series={interestSeries} width={680} height={260}
            style="area" xFormat={(v) => `${Math.round(v)}y`} yFormat={(v) => fmt(v, 'short')} />
        </div>
        <div className="card">
          <h3 className="card-title">Sensitivity · investment return</h3>
          <p className="card-sub">How investing wealth shifts with the assumed return</p>
          <SensitivityTable inputs={inputs} fmtMode={fmtMode} />
        </div>
      </div>
    </div>
  );
}

function SensitivityTable({ inputs, fmtMode }) {
  const base = baseFromInputs(inputs);
  const returns = [0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09];
  const ovr = ME.simulate({ ...base, strategy: 'overpay' });
  const ovrWealth = ovr.finalInvested - ovr.finalBalance;
  const rows = returns.map((r) => {
    const inv = ME.simulate({ ...base, strategy: 'invest', investReturn: r });
    const net = inv.finalInvested - inv.finalBalance;
    return { r, portfolio: inv.finalInvested, net, vsOver: net - ovrWealth };
  });
  const th = () => ({ textAlign: 'left', padding: '10px 14px', fontSize: 11, color: 'var(--ink-2)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' });
  const td = () => ({ padding: '10px 14px', color: 'var(--ink-0)' });
  return (
    <div style={{ overflow: 'hidden', borderRadius: 12, border: '1px solid var(--line)' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: 'var(--font-mono)', fontSize: 13 }}>
        <thead>
          <tr style={{ background: 'var(--glass-2)' }}>
            <th style={th()}>Return</th><th style={th()}>Portfolio</th><th style={th()}>Net wealth</th><th style={th()}>vs Overpay</th>
          </tr>
        </thead>
        <tbody>
          {rows.map((r) =>
            <tr key={r.r} style={{ borderTop: '1px solid var(--line)' }}>
              <td style={td()}>{(r.r * 100).toFixed(0)}%</td>
              <td style={td()}>{fmt(r.portfolio, fmtMode)}</td>
              <td style={td()}>{fmt(r.net, fmtMode)}</td>
              <td style={{ ...td(), color: r.vsOver > 0 ? 'var(--c-good)' : 'var(--c-warn)' }}>
                {r.vsOver > 0 ? '+' : ''}{fmt(r.vsOver, fmtMode)}
              </td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
}

// ---------- LEARN ----------
function LearnScreen() {
  const cards = [
    {
      kicker: '01 · The decision',
      title: 'Overpay the mortgage, or invest the difference?',
      body: 'It comes down to one comparison: your mortgage rate versus the return you can earn elsewhere. Overpaying is a guaranteed, tax-free return equal to your mortgage rate. Investing is a higher expected return — but with risk and no guarantee.',
      bullets: [
        'Mortgage rate > expected net return → overpaying usually wins',
        'Expected net return > mortgage rate → investing usually wins',
        'Overpaying is certain; investing is probable. That gap is the price of risk',
      ],
    },
    {
      kicker: '02 · Interest-only',
      title: 'Why interest-only changes everything',
      body: 'On an interest-only mortgage your monthly payment never touches the capital — you owe the full balance at the end of the term. You either overpay to chip away at it, or build a separate investment pot to repay it in one go.',
      bullets: [
        'The standard balance line stays flat for the whole term',
        'You MUST have a repayment plan for the capital',
        'Investing to clear the capital is the classic (and often stronger) play',
      ],
    },
    {
      kicker: '03 · The 10% rule',
      title: 'Watch the overpayment allowance',
      body: 'Most fixed-rate deals let you overpay up to 10% of the outstanding balance each year with no penalty. Go above that during the fixed period and you can trigger an early repayment charge (ERC) — often 1–5% of the amount.',
      bullets: [
        'The 10% resets each year, usually on the deal anniversary',
        'Lump sums count toward the same allowance',
        'Once you revert to the SVR, overpayments are normally unlimited',
      ],
    },
    {
      kicker: '04 · The whole picture',
      title: 'Beyond the headline number',
      body: 'The maths is only part of it. Clearing a mortgage early brings real peace of mind and lower monthly outgoings; investing keeps your money liquid and working. The right answer depends on your rate, your risk appetite, and how much certainty is worth to you.',
      bullets: [
        'Keep an emergency fund before overpaying or investing',
        'A Stocks & Shares ISA shelters investment gains from tax',
        'Overpaying reduces your LTV — which can unlock cheaper remortgage rates',
      ],
    },
  ];
  return (
    <div className="grid grid-2">
      {cards.map((c, i) =>
        <div key={i} className="learn-card">
          <div className="kicker">{c.kicker}</div>
          <h3>{c.title}</h3>
          <p>{c.body}</p>
          <ul>{c.bullets.map((b, j) => <li key={j}>{b}</li>)}</ul>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { DashboardScreen, CalculatorScreen, ChartsScreen, LearnScreen, AnimatedNumber, baseFromInputs });
