// Loan tool — supporting components.
//
// Kept separate from the main loan-apr-tool.jsx so that file stays focused on
// composing the page layout. Components defined here:
//   - SegmentedToggle  — small uppercase mono pill toggle
//   - PrincipalInterestPie — donut chart for principal vs interest
//   - AnnualAmortTable — yearly summary table (year, balance, principal, interest, balloon)
//   - ChartFrame — wraps any chart with a header + zoom-to-focus button + modal
//
// All components are exported on `window` so loan-apr-tool.jsx can use them.

const { useState: ltUseState, useMemo: ltUseMemo, useEffect: ltUseEffect } = React;

// ─────────────────────────────────────────────────────────────────
// SegmentedToggle — uppercase mono pill, used for unit pickers.
// Pass opts = [{ id, label }, ...]; value/onChange like a controlled input.
// ─────────────────────────────────────────────────────────────────
function SegmentedToggle({ value, onChange, opts, size = 'md', fullWidth = false }) {
  const padY = size === 'sm' ? 4 : 6;
  const padX = size === 'sm' ? 10 : 14;
  const fontSize = size === 'sm' ? 10 : 11;
  return (
    <div style={{
      display: fullWidth ? 'flex' : 'inline-flex',
      width: fullWidth ? '100%' : undefined,
      border: '1px solid var(--pdt-line)',
      background: 'var(--pdt-paper)',
    }}>
      {opts.map((o, i) => (
        <button
          key={o.id}
          type="button"
          onClick={() => onChange(o.id)}
          style={{
            flex: fullWidth ? '1 1 0' : undefined,
            padding: `${padY}px ${padX}px`,
            border: 'none',
            borderLeft: i === 0 ? 'none' : '1px solid var(--pdt-line)',
            background: value === o.id ? 'var(--pdt-forest)' : 'transparent',
            color: value === o.id ? '#fff' : 'var(--pdt-ink)',
            fontFamily: 'var(--pdt-mono)', fontSize,
            letterSpacing: '0.06em', textTransform: 'uppercase',
            fontWeight: 500, cursor: 'pointer',
          }}
        >
          {o.label}
        </button>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────
// PrincipalInterestPie — donut chart for principal vs interest split.
// Used twice: once for the bank's view, once for "your view" with extras.
// ─────────────────────────────────────────────────────────────────
function PrincipalInterestPie({
  principal, interest, balloonLump = 0,
  size = 200, label,
  // When true, the "Principal owed at balloon" legend row is rendered even
  // if balloonLump is 0 (used on the With-Extras column when its sibling
  // Bank column has a balloon — keeps both legends visually parallel).
  showBalloonRowWhenZero = false,
  // When set, the pie's *visual area* scales as (total / scaleMax). Used to
  // make the "with extras" pie physically smaller than the bank pie, since
  // the borrower paid less total. Same canvas size, smaller pie inside it.
  scaleMax,
}) {
  // Note: `principal` is the total loan principal, which already includes
  // the balloon piece. So total cost = interest + principal (NOT
  // interest + principal + balloonLump — that double-counts).
  const total = principal + interest;
  if (total <= 0) return null;

  // Compute scaled radius. Pies use AREA = π·r², so scale linear radius by
  // sqrt(total/scaleMax) to make the area itself proportional.
  const scaleRatio = scaleMax && scaleMax > 0
    ? Math.sqrt(Math.min(1, total / scaleMax))
    : 1;

  // Donut geometry: 3 segments — principal, interest, balloon (if any).
  const cx = size / 2, cy = size / 2;
  const rOuter = (size / 2 - 4) * scaleRatio;
  const rInner = rOuter * 0.58;

  // When there's a balloon, "principal" splits into two visually distinct slices:
  //   - principal paid down (forest) — what you actually own
  //   - principal still owed at balloon (amber) — what gets refinanced
  // The "principal" passed in is total loan principal; what's actually paid
  // down is principal − balloonLump.
  const principalPaidDown = balloonLump > 0
    ? Math.max(0, principal - balloonLump)
    : principal;

  // Build legend rows (used in the right-side legend list). These ALWAYS
  // include the balloon row if showBalloonRowWhenZero, even at 0%.
  const showBalloonSlice = balloonLump > 0 || showBalloonRowWhenZero;
  const legendRows = [
    { value: interest,          color: 'var(--pdt-ink)',    label: 'Interest paid' },
    { value: principalPaidDown, color: 'var(--pdt-forest)', label: showBalloonSlice ? 'Principal paid down' : 'Principal' },
  ];
  if (showBalloonSlice) {
    legendRows.push({ value: balloonLump, color: 'var(--pdt-amber)', label: 'Principal owed at balloon' });
  }

  // Build arc segs — skip 0-value slices (no zero-area arc).
  const segs = legendRows.filter((r) => r.value > 0);

  // Compute arc paths.
  let cumAngle = -Math.PI / 2; // start at top
  const arcs = segs.map((seg, i) => {
    const frac = seg.value / total;
    const sweep = frac * 2 * Math.PI;
    const a0 = cumAngle;
    const a1 = cumAngle + sweep;
    cumAngle = a1;

    const largeArc = sweep > Math.PI ? 1 : 0;
    const x0o = cx + rOuter * Math.cos(a0);
    const y0o = cy + rOuter * Math.sin(a0);
    const x1o = cx + rOuter * Math.cos(a1);
    const y1o = cy + rOuter * Math.sin(a1);
    const x0i = cx + rInner * Math.cos(a1);
    const y0i = cy + rInner * Math.sin(a1);
    const x1i = cx + rInner * Math.cos(a0);
    const y1i = cy + rInner * Math.sin(a0);

    const d = [
      `M ${x0o.toFixed(2)} ${y0o.toFixed(2)}`,
      `A ${rOuter} ${rOuter} 0 ${largeArc} 1 ${x1o.toFixed(2)} ${y1o.toFixed(2)}`,
      `L ${x0i.toFixed(2)} ${y0i.toFixed(2)}`,
      `A ${rInner} ${rInner} 0 ${largeArc} 0 ${x1i.toFixed(2)} ${y1i.toFixed(2)}`,
      'Z',
    ].join(' ');

    return { ...seg, d, frac };
  });

  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 24, flexWrap: 'wrap',
    }}>
      <svg
        width={size} height={size}
        viewBox={`0 0 ${size} ${size}`}
        style={{ flex: '0 0 auto' }}
      >
        {arcs.map((a, i) => (
          <path
            key={i}
            d={a.d}
            fill={a.color}
            stroke="var(--pdt-paper)"
            strokeWidth={1.5}
          />
        ))}
        {label && (
          <>
            <text
              x={cx} y={cy - 4}
              textAnchor="middle"
              fontFamily="var(--pdt-mono)"
              fontSize="9"
              fill="var(--pdt-mute)"
              letterSpacing="0.08em"
            >
              {label.toUpperCase()}
            </text>
            <text
              x={cx} y={cy + 12}
              textAnchor="middle"
              fontFamily="var(--pdt-sans)"
              fontSize="14"
              fontWeight="500"
              fill="var(--pdt-ink)"
            >
              {fmtMoney(total)}
            </text>
          </>
        )}
      </svg>

      <div style={{ flex: '1 1 180px', minWidth: 180 }}>
        {legendRows.map((a, i) => {
          const frac = total > 0 ? a.value / total : 0;
          return (
          <div key={i} style={{
            display: 'flex', alignItems: 'baseline', gap: 10,
            paddingBottom: 8, marginBottom: 8,
            borderBottom: i === legendRows.length - 1
              ? 'none'
              : '1px solid var(--pdt-line-soft)',
          }}>
            <span style={{
              width: 12, height: 12, background: a.color,
              flex: '0 0 auto', alignSelf: 'center',
            }} />
            <div style={{ flex: 1 }}>
              <div style={{
                fontFamily: 'var(--pdt-mono)', fontSize: 10,
                color: 'var(--pdt-mute)', letterSpacing: '0.06em',
                textTransform: 'uppercase',
              }}>
                {a.label}
              </div>
              <div style={{
                fontFamily: 'var(--pdt-sans)', fontSize: 16, fontWeight: 500,
                color: 'var(--pdt-ink)', letterSpacing: '-0.01em',
              }}>
                {fmtMoneyFull(a.value)}
              </div>
            </div>
            <div style={{
              fontFamily: 'var(--pdt-mono)', fontSize: 11,
              color: 'var(--pdt-mute)', letterSpacing: '0.04em',
            }}>
              {(frac * 100).toFixed(1)}%
            </div>
          </div>
          );
        })}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────
// AnnualAmortTable — yearly summary of the schedule.
// Shows: year, ending balance, principal paid, interest paid, balloon (if any).
// Folds a 12-month schedule into yearly buckets.
// ─────────────────────────────────────────────────────────────────
function AnnualAmortTable({ schedule, balloonMonth, balloonLump }) {
  if (!schedule || schedule.length === 0) return null;

  const lastM = schedule.length;
  const lastYear = Math.ceil(lastM / 12);

  const rows = [];
  for (let yr = 1; yr <= lastYear; yr++) {
    const startM = (yr - 1) * 12 + 1;
    const endM = Math.min(yr * 12, lastM);
    if (startM > lastM) break;
    let yearPrincipal = 0;
    let yearInterest = 0;
    let endBalance = 0;
    for (let m = startM; m <= endM; m++) {
      const row = schedule[m - 1];
      yearPrincipal += row.principalPaid;
      yearInterest += row.interest;
      endBalance = row.balance;
    }
    const isBalloonYear = balloonMonth && balloonMonth >= startM && balloonMonth <= endM;
    rows.push({
      year: yr,
      principal: yearPrincipal,
      interest: yearInterest,
      balance: endBalance,
      balloon: isBalloonYear ? balloonLump : null,
    });
  }

  const headerCell = {
    padding: '10px 14px',
    fontFamily: 'var(--pdt-mono)', fontSize: 10,
    letterSpacing: '0.08em', textTransform: 'uppercase',
    color: 'var(--pdt-mute)', fontWeight: 500,
    textAlign: 'right',
    borderBottom: '1px solid var(--pdt-line)',
  };
  const cell = {
    padding: '10px 14px',
    fontFamily: 'var(--pdt-mono)', fontSize: 13,
    color: 'var(--pdt-ink)',
    textAlign: 'right',
    borderBottom: '1px solid var(--pdt-line-soft)',
  };

  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{
        width: '100%', borderCollapse: 'collapse',
        fontFamily: 'var(--pdt-mono)',
      }}>
        <thead>
          <tr>
            <th style={{ ...headerCell, textAlign: 'left' }}>Year</th>
            <th style={headerCell}>Principal paid</th>
            <th style={headerCell}>Interest paid</th>
            <th style={headerCell}>Ending balance</th>
            <th style={headerCell}>Balloon</th>
          </tr>
        </thead>
        <tbody>
          {rows.map((r, i) => (
            <tr key={r.year} style={{
              background: r.balloon
                ? 'rgba(196, 123, 58, 0.06)'
                : (i % 2 === 0 ? 'var(--pdt-paper)' : 'var(--pdt-paper-deep)'),
            }}>
              <td style={{ ...cell, textAlign: 'left', fontWeight: 500 }}>
                {r.year}
              </td>
              <td style={cell}>{fmtMoneyFull(r.principal)}</td>
              <td style={cell}>{fmtMoneyFull(r.interest)}</td>
              <td style={cell}>{fmtMoneyFull(r.balance)}</td>
              <td style={{ ...cell, color: r.balloon ? 'var(--pdt-amber)' : 'var(--pdt-mute)' }}>
                {r.balloon ? fmtMoneyFull(r.balloon) : '—'}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────
// ChartFrame — wraps any chart/visual with a card chrome (eyebrow, optional
// legend, zoom-to-focus button) and a modal overlay for fullscreen.
// Children should be the chart contents; pass `legend` for the inline legend.
// ─────────────────────────────────────────────────────────────────
function ChartFrame({ title, legend, children, footnote, headerNote }) {
  const [zoomed, setZoomed] = ltUseState(false);

  // Lock body scroll when zoomed. Also broadcast a custom event so other
  // page-level UI (e.g. the floating extra-payment bar) can react and stay
  // visible above the modal backdrop.
  ltUseEffect(() => {
    window.dispatchEvent(new CustomEvent('chartframe:zoom', { detail: { zoomed } }));
    if (!zoomed) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const onKey = (e) => { if (e.key === 'Escape') setZoomed(false); };
    window.addEventListener('keydown', onKey);
    return () => {
      document.body.style.overflow = prev;
      window.removeEventListener('keydown', onKey);
    };
  }, [zoomed]);

  const headerBar = (
    <div style={{
      display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start',
      marginBottom: 16, gap: 12,
    }}>
      <div style={{
        display: 'flex', alignItems: 'baseline', gap: 16,
        flexWrap: 'wrap', flex: 1, minWidth: 0,
      }}>
        <div className="t-eyebrow" style={{ color: 'var(--pdt-mute)' }}>
          {title}
        </div>
        {legend && (
          <div style={{
            display: 'flex', gap: 16, flexWrap: 'wrap',
            fontFamily: 'var(--pdt-mono)', fontSize: 10,
            letterSpacing: '0.06em', color: 'var(--pdt-mute)',
          }}>
            {legend}
          </div>
        )}
      </div>
      <button
        type="button"
        onClick={() => setZoomed(!zoomed)}
        aria-label={zoomed ? 'Close fullscreen view' : 'Open fullscreen view'}
        style={{
          background: 'transparent',
          border: '1px solid var(--pdt-line)',
          padding: '4px 10px',
          fontFamily: 'var(--pdt-mono)', fontSize: 10,
          letterSpacing: '0.08em', textTransform: 'uppercase',
          color: 'var(--pdt-mute)', cursor: 'pointer',
          display: 'inline-flex', alignItems: 'center', gap: 6,
          flexShrink: 0,
        }}
        onMouseEnter={(e) => {
          e.currentTarget.style.borderColor = 'var(--pdt-forest)';
          e.currentTarget.style.color = 'var(--pdt-forest)';
        }}
        onMouseLeave={(e) => {
          e.currentTarget.style.borderColor = 'var(--pdt-line)';
          e.currentTarget.style.color = 'var(--pdt-mute)';
        }}
      >
        {/* Tiny corner-out icon */}
        <svg width="11" height="11" viewBox="0 0 11 11" fill="none" stroke="currentColor" strokeWidth="1.4">
          {zoomed ? (
            <>
              <path d="M 4 1 L 1 1 L 1 4" />
              <path d="M 7 10 L 10 10 L 10 7" />
              <path d="M 1 1 L 4 4" />
              <path d="M 10 10 L 7 7" />
            </>
          ) : (
            <>
              <path d="M 1 4 L 1 1 L 4 1" />
              <path d="M 10 7 L 10 10 L 7 10" />
            </>
          )}
        </svg>
        {zoomed ? 'Close' : 'Focus'}
      </button>
    </div>
  );

  const card = (
    <div style={{
      background: 'var(--pdt-paper)',
      border: '1px solid var(--pdt-line)',
      padding: 'clamp(20px, 3vw, 28px)',
    }}>
      {headerBar}
      {headerNote && (
        <div style={{
          marginBottom: 18, fontFamily: 'var(--pdt-serif)', fontStyle: 'italic',
          fontSize: 14, lineHeight: 1.55, color: 'var(--pdt-ink-soft)',
        }}>
          {headerNote}
        </div>
      )}
      {children}
      {footnote && (
        <div style={{
          marginTop: 14, fontFamily: 'var(--pdt-serif)', fontStyle: 'italic',
          fontSize: 14, lineHeight: 1.55, color: 'var(--pdt-ink-soft)',
        }}>
          {footnote}
        </div>
      )}
    </div>
  );

  if (!zoomed) return card;

  // Fullscreen modal
  return (
    <>
      {card}
      <div
        onClick={() => setZoomed(false)}
        style={{
          position: 'fixed', inset: 0, zIndex: 1000,
          background: 'rgba(15, 23, 23, 0.7)',
          backdropFilter: 'blur(4px)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 'clamp(16px, 4vw, 48px)',
        }}
      >
        <div
          onClick={(e) => e.stopPropagation()}
          style={{
            background: 'var(--pdt-paper)',
            border: '1px solid var(--pdt-line)',
            padding: 'clamp(24px, 4vw, 48px)',
            width: '100%', maxWidth: 1400, maxHeight: '90vh',
            overflow: 'auto',
            boxShadow: '0 30px 60px rgba(0,0,0,0.3)',
          }}
        >
          {headerBar}
          <div style={{ minHeight: 'min(560px, 70vh)' }}>
            {children}
          </div>
          {footnote && (
            <div style={{
              marginTop: 18, fontFamily: 'var(--pdt-serif)', fontStyle: 'italic',
              fontSize: 16, lineHeight: 1.6, color: 'var(--pdt-ink-soft)',
            }}>
              {footnote}
            </div>
          )}
        </div>
      </div>
    </>
  );
}

// Export to window so loan-apr-tool.jsx can use them
window.SegmentedToggle = SegmentedToggle;
window.PrincipalInterestPie = PrincipalInterestPie;
window.AnnualAmortTable = AnnualAmortTable;
window.ChartFrame = ChartFrame;
