// charts.jsx — SVG-based line/area/bar charts. Exports to window.
// Avoids external chart libs. Themes via CSS vars.

const { useState, useRef, useEffect, useMemo } = React;

function LineChart({
  series,            // [{ key, label, color, points: [{x, y}], dashed? }]
  width = 720, height = 320,
  padding = { t: 20, r: 24, b: 32, l: 56 },
  xLabel = '', yLabel = '',
  yFormat = (v) => v,
  xFormat = (v) => v,
  style = 'line',    // 'line' | 'area' | 'bar'
  highlightX = null, // optional vertical guide at given x
  highlightLabel = null,
}) {
  const [hover, setHover] = useState(null);
  const svgRef = useRef(null);

  const allPoints = series.flatMap(s => s.points);
  const xs = allPoints.map(p => p.x);
  const ys = allPoints.map(p => p.y);
  const xMin = Math.min(...xs), xMax = Math.max(...xs);
  let yMin = Math.min(0, ...ys), yMax = Math.max(...ys);
  if (yMin === yMax) yMax = yMin + 1;
  const yRange = yMax - yMin;
  yMax += yRange * 0.05;
  yMin -= yRange * 0.02;

  const plotW = width - padding.l - padding.r;
  const plotH = height - padding.t - padding.b;
  const sx = (x) => padding.l + ((x - xMin) / (xMax - xMin || 1)) * plotW;
  const sy = (y) => padding.t + (1 - (y - yMin) / (yMax - yMin)) * plotH;

  // y-axis ticks
  const yTickCount = 5;
  const yTicks = Array.from({ length: yTickCount }, (_, i) => yMin + ((yMax - yMin) / (yTickCount - 1)) * i);
  const xTickCount = Math.min(6, Math.floor(xMax - xMin) + 1);
  const xTicks = Array.from({ length: xTickCount }, (_, i) => xMin + ((xMax - xMin) / (xTickCount - 1)) * i);

  // hover handler
  function onMove(e) {
    const svg = svgRef.current;
    if (!svg) return;
    const pt = svg.createSVGPoint();
    pt.x = e.clientX; pt.y = e.clientY;
    const m = pt.matrixTransform(svg.getScreenCTM().inverse());
    const xVal = xMin + ((m.x - padding.l) / plotW) * (xMax - xMin);
    if (m.x < padding.l || m.x > padding.l + plotW) { setHover(null); return; }
    // find nearest point per series
    const nearest = series.map(s => {
      let best = null, bd = Infinity;
      s.points.forEach(p => {
        const d = Math.abs(p.x - xVal);
        if (d < bd) { bd = d; best = p; }
      });
      return { key: s.key, label: s.label, color: s.color, point: best };
    });
    setHover({ x: nearest[0]?.point.x, items: nearest });
  }

  const linePath = (pts) => pts.map((p, i) => `${i === 0 ? 'M' : 'L'} ${sx(p.x)} ${sy(p.y)}`).join(' ');
  const areaPath = (pts) => {
    if (!pts.length) return '';
    const top = pts.map((p, i) => `${i === 0 ? 'M' : 'L'} ${sx(p.x)} ${sy(p.y)}`).join(' ');
    const bottom = `L ${sx(pts[pts.length - 1].x)} ${sy(yMin)} L ${sx(pts[0].x)} ${sy(yMin)} Z`;
    return top + ' ' + bottom;
  };

  return (
    <div style={{ position: 'relative', width: '100%' }}>
      <svg ref={svgRef} viewBox={`0 0 ${width} ${height}`} width="100%"
           style={{ display: 'block', overflow: 'visible' }}
           onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
        <defs>
          {series.map(s => (
            <linearGradient key={`g-${s.key}`} id={`grad-${s.key}`} x1="0" x2="0" y1="0" y2="1">
              <stop offset="0%" stopColor={s.color} stopOpacity="0.35" />
              <stop offset="100%" stopColor={s.color} stopOpacity="0" />
            </linearGradient>
          ))}
        </defs>

        {/* y grid */}
        {yTicks.map((t, i) => (
          <g key={`yt-${i}`}>
            <line x1={padding.l} x2={width - padding.r} y1={sy(t)} y2={sy(t)}
                  stroke="var(--line)" strokeDasharray="2 4" />
            <text x={padding.l - 10} y={sy(t)} dy="0.32em" textAnchor="end"
                  fontSize="11" fill="var(--ink-3)" fontFamily="var(--font-mono)">
              {yFormat(t)}
            </text>
          </g>
        ))}
        {/* x ticks */}
        {xTicks.map((t, i) => (
          <text key={`xt-${i}`} x={sx(t)} y={height - padding.b + 18} textAnchor="middle"
                fontSize="11" fill="var(--ink-3)" fontFamily="var(--font-mono)">
            {xFormat(t)}
          </text>
        ))}

        {/* highlight (e.g. write-off year) */}
        {highlightX != null && (
          <g>
            <line x1={sx(highlightX)} x2={sx(highlightX)} y1={padding.t} y2={height - padding.b}
                  stroke="var(--c-warn)" strokeDasharray="4 4" opacity="0.5" />
            {highlightLabel && (
              <text x={sx(highlightX) + 6} y={padding.t + 12} fill="var(--c-warn)" fontSize="11"
                    fontFamily="var(--font-mono)">{highlightLabel}</text>
            )}
          </g>
        )}

        {/* series */}
        {series.map(s => (
          <g key={`s-${s.key}`}>
            {style === 'area' && <path d={areaPath(s.points)} fill={`url(#grad-${s.key})`} stroke="none" />}
            {style !== 'bar' && (
              <path d={linePath(s.points)} stroke={s.color} strokeWidth="2" fill="none"
                    strokeDasharray={s.dashed ? '4 4' : 'none'}
                    strokeLinecap="round" strokeLinejoin="round" />
            )}
            {style === 'bar' && s.points.map((p, i) => {
              const bw = Math.max(2, (plotW / s.points.length) * 0.6 / series.length);
              const offset = (series.indexOf(s) - (series.length - 1) / 2) * bw;
              return (
                <rect key={i} x={sx(p.x) - bw / 2 + offset} y={sy(Math.max(0, p.y))}
                      width={bw} height={Math.abs(sy(p.y) - sy(0))} fill={s.color} opacity="0.85" rx="1.5" />
              );
            })}
          </g>
        ))}

        {/* hover guide */}
        {hover && (
          <g>
            <line x1={sx(hover.x)} x2={sx(hover.x)} y1={padding.t} y2={height - padding.b}
                  stroke="var(--ink-3)" strokeDasharray="2 3" />
            {hover.items.map((it, i) => (
              <circle key={i} cx={sx(it.point.x)} cy={sy(it.point.y)} r="4"
                      fill={it.color} stroke="var(--bg-0)" strokeWidth="1.5" />
            ))}
          </g>
        )}

        {/* axis labels */}
        {yLabel && (
          <text x={14} y={padding.t + plotH / 2} textAnchor="middle" fontSize="10"
                fill="var(--ink-3)" transform={`rotate(-90 14 ${padding.t + plotH / 2})`}>
            {yLabel}
          </text>
        )}
        {xLabel && (
          <text x={padding.l + plotW / 2} y={height - 4} textAnchor="middle" fontSize="10" fill="var(--ink-3)">
            {xLabel}
          </text>
        )}
      </svg>

      {hover && (
        <div className="tooltip" style={{
          left: `${(sx(hover.x) / width) * 100}%`,
          top: `${(padding.t / height) * 100}%`,
          minWidth: 180, whiteSpace: 'normal',
        }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginBottom: 6 }}>
            Year {Math.round(hover.x)}
          </div>
          {hover.items.map((it, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, fontSize: 12, padding: '2px 0' }}>
              <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ width: 8, height: 8, borderRadius: 4, background: it.color, display: 'inline-block' }} />
                {it.label}
              </span>
              <span style={{ fontFamily: 'var(--font-mono)' }}>{yFormat(it.point.y)}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function Sparkline({ points, color = 'currentColor', height = 36, fill = true }) {
  if (!points || !points.length) return null;
  const w = 200;
  const ys = points.map(p => p.y);
  const yMin = Math.min(...ys), yMax = Math.max(...ys);
  const xMin = points[0].x, xMax = points[points.length - 1].x;
  const sx = (x) => ((x - xMin) / (xMax - xMin || 1)) * w;
  const sy = (y) => height - 4 - ((y - yMin) / (yMax - yMin || 1)) * (height - 8);
  const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${sx(p.x).toFixed(1)} ${sy(p.y).toFixed(1)}`).join(' ');
  const area = fill ? `${path} L ${w} ${height} L 0 ${height} Z` : null;
  return (
    <svg viewBox={`0 0 ${w} ${height}`} className="spark" preserveAspectRatio="none">
      {fill && <path d={area} fill={color} opacity="0.15" />}
      <path d={path} fill="none" stroke={color} strokeWidth="1.8" />
    </svg>
  );
}

Object.assign(window, { LineChart, Sparkline });
