// Loan visualization: BalanceChart (bank vs accelerated balance overlay) and APRCurveChart.

// --- BalanceChart -----------------------------------------------------------
// Two balance curves on one axis. The vertical gap between them is the savings.
// Optional balloon marker if hasBalloon = true.
function BalanceChart({ scheduleBank, scheduleAccel, principal, hasBalloon, balloonMonth, payoffMonthAccel, savingsLabel }) {
  if (!scheduleBank || scheduleBank.length === 0) return null;
  const w = 640;
  const h = 260;
  const padL = 64, padR = 24, padT = 18, padB = 36;
  const innerW = w - padL - padR;
  const innerH = h - padT - padB;

  // X-axis spans the bank's full payoff (so accel curve sits inside the same frame).
  const totalMonths = scheduleBank.length;
  const totalYears = totalMonths / 12;
  const maxY = principal;

  const x = (m) => padL + ((m - 1) / Math.max(1, totalMonths - 1)) * innerW;
  const y = (v) => padT + (1 - v / maxY) * innerH;

  // Bank balance line (always full width).
  const bankPath = scheduleBank.map((s, i) =>
    `${i === 0 ? 'M' : 'L'} ${x(s.month)} ${y(s.balance)}`
  ).join(' ');

  // Accelerated balance line (may stop short).
  const accelPath = scheduleAccel.map((s, i) =>
    `${i === 0 ? 'M' : 'L'} ${x(s.month)} ${y(s.balance)}`
  ).join(' ');

  // The "savings" region — area between the two curves up to the accel payoff.
  const accelEnd = scheduleAccel[scheduleAccel.length - 1].month;
  const savingsRegion = (() => {
    let path = '';
    // Top edge: bank balance forward from month 1 to accelEnd
    scheduleBank.slice(0, accelEnd).forEach((s, i) => {
      path += `${i === 0 ? 'M' : 'L'} ${x(s.month)} ${y(s.balance)}`;
    });
    // Bottom edge: accel balance backward from accelEnd to month 1
    for (let i = scheduleAccel.length - 1; i >= 0; i--) {
      const s = scheduleAccel[i];
      path += ` L ${x(s.month)} ${y(s.balance)}`;
    }
    path += ' Z';
    return path;
  })();

  // Year ticks
  const yearTicks = [];
  const tickStep = Math.max(1, Math.ceil(totalYears / 6));
  for (let yr = 0; yr <= totalYears; yr += tickStep) {
    yearTicks.push(yr);
  }
  if (yearTicks[yearTicks.length - 1] !== Math.round(totalYears)) {
    yearTicks.push(Math.round(totalYears));
  }

  const balloonX = hasBalloon ? x(balloonMonth) : null;
  const accelPayoffX = x(payoffMonthAccel);

  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: '100%', height: 'auto', display: 'block' }}
         aria-label="Loan balance over time, bank schedule vs your schedule with extra payments">
      {/* y-axis ticks */}
      {[0, 0.25, 0.5, 0.75, 1].map((p) => {
        const yy = padT + (1 - p) * innerH;
        return (
          <g key={p}>
            <line x1={padL} x2={w - padR} y1={yy} y2={yy}
                  stroke="var(--pdt-line-soft)" strokeDasharray="2 4" />
            <text x={padL - 8} y={yy + 4} textAnchor="end"
                  fontFamily="var(--pdt-mono)" fontSize="10"
                  fill="var(--pdt-mute)">
              {fmtMoney(maxY * p)}
            </text>
          </g>
        );
      })}

      {/* Savings region */}
      <path d={savingsRegion} fill="var(--pdt-forest)" opacity="0.16" />

      {/* Bank line — heavy ink */}
      <path d={bankPath} fill="none" stroke="var(--pdt-ink)" strokeWidth="2" />

      {/* Accelerated line — green, thicker */}
      <path d={accelPath} fill="none" stroke="var(--pdt-green)" strokeWidth="2.5" />

      {/* Balloon marker — vertical dashed line + label */}
      {hasBalloon && (
        <g>
          <line x1={balloonX} x2={balloonX} y1={padT} y2={padT + innerH}
                stroke="var(--pdt-amber)" strokeWidth="1.5" strokeDasharray="4 4" />
          <text x={balloonX} y={padT - 4} textAnchor="middle"
                fontFamily="var(--pdt-mono)" fontSize="10"
                fill="var(--pdt-amber)" fontWeight="500"
                letterSpacing="0.06em">
            BALLOON
          </text>
        </g>
      )}

      {/* Accelerated payoff marker — only if payoff < bank end */}
      {scheduleAccel[scheduleAccel.length - 1].balance < 0.5 &&
       accelPayoffX < x(totalMonths) - 4 && (
        <g>
          <circle cx={accelPayoffX} cy={y(0)} r="4" fill="var(--pdt-green)" />
          <line x1={accelPayoffX} x2={accelPayoffX} y1={y(0)} y2={y(0) - 14}
                stroke="var(--pdt-green)" strokeWidth="1" />
          <text x={accelPayoffX} y={y(0) - 18} textAnchor="middle"
                fontFamily="var(--pdt-mono)" fontSize="10"
                fill="var(--pdt-forest)" fontWeight="500"
                letterSpacing="0.06em">
            PAID OFF
          </text>
        </g>
      )}

      {/* x-axis ticks */}
      {yearTicks.map((yr, i) => {
        const m = Math.max(1, yr * 12);
        const xx = x(m === 0 ? 1 : Math.min(m, totalMonths));
        return (
          <g key={i}>
            <line x1={xx} x2={xx} y1={padT + innerH} y2={padT + innerH + 4}
                  stroke="var(--pdt-line)" />
            <text x={xx} y={padT + innerH + 18} textAnchor="middle"
                  fontFamily="var(--pdt-mono)" fontSize="10"
                  fill="var(--pdt-mute)">
              yr {yr}
            </text>
          </g>
        );
      })}

      {/* baseline */}
      <line x1={padL} x2={w - padR} y1={padT + innerH} y2={padT + innerH}
            stroke="var(--pdt-line)" />

      {/* Savings annotation — rendered LAST so it paints over the lines.
          Positioned at the widest point of the gap (~55% through the
          accelerated schedule), where the two curves have diverged most. */}
      {savingsLabel && (() => {
        const midM = Math.round(accelEnd * 0.55);
        if (midM < 1) return null;
        const bankRow = scheduleBank[midM - 1];
        const accelRow = scheduleAccel[midM - 1] || scheduleAccel[scheduleAccel.length - 1];
        if (!bankRow || !accelRow) return null;
        const labelX = x(midM);
        const labelY = (y(bankRow.balance) + y(accelRow.balance)) / 2;
        return (
          <g style={{ pointerEvents: 'none' }}>
            <rect
              x={labelX - 64} y={labelY - 14}
              width={128} height={28}
              fill="var(--pdt-paper)"
              stroke="var(--pdt-green)"
              strokeWidth="1"
            />
            <text
              x={labelX} y={labelY + 4}
              textAnchor="middle"
              fontFamily="var(--pdt-mono)"
              fontSize="11"
              fontWeight="500"
              fill="var(--pdt-forest-deep)"
              letterSpacing="0.04em"
            >
              {savingsLabel}
            </text>
          </g>
        );
      })()}
    </svg>
  );
}

// Plots effective APR if you exited at each month. With financed fees, this
// curve starts above the stated rate and decays toward it as the term progresses.
function APRCurveChart({ aprCurve, statedRate }) {
  if (!aprCurve || aprCurve.length === 0) return null;
  const w = 640;
  const h = 180;
  const padL = 64, padR = 24, padT = 18, padB = 32;
  const innerW = w - padL - padR;
  const innerH = h - padT - padB;
  const n = aprCurve.length;

  // Y range — clamp absurd month-1 spikes for readability.
  const aprs = aprCurve.map((p) => p.apr).filter((v) => isFinite(v));
  let maxApr = Math.max(statedRate * 2.2, ...aprs.slice(Math.floor(n * 0.05)));
  if (!isFinite(maxApr) || maxApr <= 0) maxApr = statedRate * 2;
  let minApr = Math.min(statedRate * 0.85, ...aprs);
  if (!isFinite(minApr) || minApr < 0) minApr = 0;

  const x = (m) => padL + ((m - 1) / Math.max(1, n - 1)) * innerW;
  const y = (v) => {
    const clamped = Math.max(minApr, Math.min(maxApr, v));
    return padT + (1 - (clamped - minApr) / (maxApr - minApr)) * innerH;
  };

  const path = aprCurve.map((p, i) => {
    const yv = isFinite(p.apr) ? p.apr : statedRate;
    return `${i === 0 ? 'M' : 'L'} ${x(p.month)} ${y(yv)}`;
  }).join(' ');

  // Stated-rate reference line.
  const refY = y(statedRate);

  // Year ticks
  const totalYears = n / 12;
  const yearTicks = [];
  const tickStep = Math.max(1, Math.ceil(totalYears / 6));
  for (let yr = 0; yr <= totalYears; yr += tickStep) yearTicks.push(yr);
  if (yearTicks[yearTicks.length - 1] !== Math.round(totalYears)) {
    yearTicks.push(Math.round(totalYears));
  }

  // Y axis ticks — round-ish numbers
  const yTicks = [];
  const range = maxApr - minApr;
  const step = range > 8 ? 4 : range > 4 ? 2 : 1;
  for (let v = Math.ceil(minApr); v <= maxApr; v += step) yTicks.push(v);

  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: '100%', height: 'auto', display: 'block' }}
         aria-label="Effective APR over time if you paid off at each month">
      {/* Y grid */}
      {yTicks.map((v) => (
        <g key={v}>
          <line x1={padL} x2={w - padR} y1={y(v)} y2={y(v)}
                stroke="var(--pdt-line-soft)" strokeDasharray="2 4" />
          <text x={padL - 8} y={y(v) + 4} textAnchor="end"
                fontFamily="var(--pdt-mono)" fontSize="10"
                fill="var(--pdt-mute)">
            {v.toFixed(1)}%
          </text>
        </g>
      ))}

      {/* Stated rate reference */}
      <line x1={padL} x2={w - padR} y1={refY} y2={refY}
            stroke="var(--pdt-mute)" strokeWidth="1" strokeDasharray="3 4" />
      <text x={w - padR} y={refY - 4} textAnchor="end"
            fontFamily="var(--pdt-mono)" fontSize="10"
            fill="var(--pdt-mute)" letterSpacing="0.06em">
        STATED RATE {statedRate.toFixed(2)}%
      </text>

      {/* APR curve */}
      <path d={path} fill="none" stroke="var(--pdt-amber)" strokeWidth="2.5" />

      {/* X ticks */}
      {yearTicks.map((yr, i) => {
        const m = Math.max(1, yr * 12);
        const xx = x(m === 0 ? 1 : Math.min(m, n));
        return (
          <g key={i}>
            <line x1={xx} x2={xx} y1={padT + innerH} y2={padT + innerH + 4}
                  stroke="var(--pdt-line)" />
            <text x={xx} y={padT + innerH + 18} textAnchor="middle"
                  fontFamily="var(--pdt-mono)" fontSize="10"
                  fill="var(--pdt-mute)">
              yr {yr}
            </text>
          </g>
        );
      })}

      <line x1={padL} x2={w - padR} y1={padT + innerH} y2={padT + innerH}
            stroke="var(--pdt-line)" />
    </svg>
  );
}

window.BalanceChart = BalanceChart;
window.APRCurveChart = APRCurveChart;
