/* charts.jsx — minimal SVG charts in Recharts visual style.
   LineChart: forecast vs actual vs capacity.
   StackedBar: layered counts.
   No deps beyond React. */

function useChartSize(ref) {
  const [w, setW] = React.useState(800);
  React.useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(entries => {
      for (const e of entries) setW(Math.max(240, Math.floor(e.contentRect.width)));
    });
    ro.observe(ref.current);
    return () => ro.disconnect();
  }, [ref]);
  return w;
}

function niceTicks(max, n = 5) {
  if (max === 0) return [0];
  const step = Math.pow(10, Math.floor(Math.log10(max / n)));
  const err = (n / max) * step;
  let m = 1;
  if (err <= 0.15) m = 10;
  else if (err <= 0.35) m = 5;
  else if (err <= 0.75) m = 2;
  const niceStep = m * step;
  const out = [];
  for (let v = 0; v <= max + 0.001; v += niceStep) out.push(v);
  if (out[out.length - 1] < max) out.push(out[out.length - 1] + niceStep);
  return out;
}

function LineChart({ data, height = 220, lines, xKey = 'date' }) {
  const ref = React.useRef(null);
  const w = useChartSize(ref);
  const [hover, setHover] = React.useState(null);

  const padding = { top: 16, right: 16, bottom: 28, left: 44 };
  const innerW = w - padding.left - padding.right;
  const innerH = height - padding.top - padding.bottom;

  const allValues = [];
  lines.forEach(l => data.forEach(d => { if (d[l.key] != null) allValues.push(d[l.key]); }));
  const maxV = Math.max(...allValues, 0);
  const ticks = niceTicks(maxV, 4);
  const top = ticks[ticks.length - 1] || 1;

  const x = (i) => padding.left + (i * innerW) / Math.max(1, data.length - 1);
  const y = (v) => padding.top + innerH - (v / top) * innerH;

  function buildPath(line) {
    let d = '';
    let started = false;
    data.forEach((row, i) => {
      const v = row[line.key];
      if (v == null) { started = false; return; }
      d += (started ? ' L' : 'M') + x(i) + ' ' + y(v);
      started = true;
    });
    return d;
  }

  return (
    <div ref={ref} style={{ width: '100%', position: 'relative', userSelect: 'none' }}>
      <svg width={w} height={height} style={{ display: 'block', overflow: 'visible' }}
           onMouseLeave={() => setHover(null)}>
        {/* y grid */}
        {ticks.map(t => (
          <g key={t}>
            <line x1={padding.left} x2={w - padding.right} y1={y(t)} y2={y(t)}
              stroke="#ececec" strokeDasharray={t === 0 ? '0' : '3 3'}/>
            <text x={padding.left - 8} y={y(t) + 4} fontSize="10" fill="#99a1af" textAnchor="end"
              style={{ fontFamily: 'var(--bx-font-mono)', fontVariantNumeric: 'tabular-nums' }}>
              {t >= 1000 ? (t / 1000).toFixed(t < 10000 ? 1 : 0) + 'k' : t}
            </text>
          </g>
        ))}
        {/* x labels */}
        {data.map((row, i) => {
          if (i % Math.ceil(data.length / 8) !== 0 && i !== data.length - 1) return null;
          const label = row.label || row[xKey];
          return (
            <text key={i} x={x(i)} y={height - 8} fontSize="10" fill="#99a1af" textAnchor="middle"
              style={{ fontFamily: 'var(--bx-font-sans)' }}>
              {typeof label === 'string' && label.length > 8 ? label.slice(5) : label}
            </text>
          );
        })}
        {/* lines */}
        {lines.map(line => (
          <path key={line.key} d={buildPath(line)} stroke={line.color}
            strokeWidth={line.width || 2}
            strokeDasharray={line.dashed ? '4 4' : '0'}
            fill="none" strokeLinejoin="round" strokeLinecap="round"/>
        ))}
        {/* points + hover */}
        {data.map((row, i) => (
          <g key={i}>
            <rect x={x(i) - innerW / data.length / 2} y={padding.top}
              width={innerW / data.length} height={innerH} fill="transparent"
              onMouseEnter={() => setHover(i)}/>
            {hover === i && (
              <line x1={x(i)} x2={x(i)} y1={padding.top} y2={padding.top + innerH}
                stroke="#0b43ea" strokeWidth="1" strokeDasharray="2 2" opacity="0.4"/>
            )}
            {lines.map(line => row[line.key] != null && (
              <circle key={line.key} cx={x(i)} cy={y(row[line.key])} r={hover === i ? 4 : 2.5}
                fill={line.color} stroke="#fff" strokeWidth="1.5"/>
            ))}
          </g>
        ))}
      </svg>
      {/* tooltip */}
      {hover !== null && (
        <div style={{
          position: 'absolute', left: Math.min(w - 200, Math.max(0, x(hover) - 90)),
          top: 6, background: '#fff', border: '1px solid var(--bx-border-muted)',
          borderRadius: 8, padding: '8px 10px', boxShadow: 'var(--bx-shadow-pop)',
          pointerEvents: 'none', minWidth: 180, fontSize: 11.5,
        }}>
          <div style={{ fontWeight: 600, color: 'var(--bx-text-heading)', marginBottom: 4 }}>
            {data[hover][xKey]}
          </div>
          {lines.map(l => (
            <div key={l.key} style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--bx-text-body)' }}>
              <span style={{ width: 8, height: 8, background: l.color, borderRadius: 9999 }}></span>
              <span style={{ flex: 1 }}>{l.label}</span>
              <span style={{ fontFamily: 'var(--bx-font-mono)', fontVariantNumeric: 'tabular-nums', fontWeight: 600, color: 'var(--bx-text-dark)' }}>
                {data[hover][l.key] == null ? '—' : Number(data[hover][l.key]).toLocaleString('en-US')}
              </span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function StackedBar({ data, height = 220, stacks, xKey = 'label' }) {
  const ref = React.useRef(null);
  const w = useChartSize(ref);
  const [hover, setHover] = React.useState(null);

  const padding = { top: 16, right: 16, bottom: 32, left: 44 };
  const innerW = w - padding.left - padding.right;
  const innerH = height - padding.top - padding.bottom;

  const totals = data.map(d => stacks.reduce((s, st) => s + (d[st.key] || 0), 0));
  const maxV = Math.max(...totals, 0);
  const ticks = niceTicks(maxV, 4);
  const top = ticks[ticks.length - 1] || 1;
  const barW = Math.min(36, (innerW / data.length) * 0.62);
  const groupW = innerW / data.length;
  const x = (i) => padding.left + groupW * i + groupW / 2;
  const y = (v) => padding.top + innerH - (v / top) * innerH;

  return (
    <div ref={ref} style={{ width: '100%', position: 'relative' }}>
      <svg width={w} height={height} style={{ display: 'block' }}>
        {ticks.map(t => (
          <g key={t}>
            <line x1={padding.left} x2={w - padding.right} y1={y(t)} y2={y(t)}
              stroke="#ececec" strokeDasharray={t === 0 ? '0' : '3 3'}/>
            <text x={padding.left - 8} y={y(t) + 4} fontSize="10" fill="#99a1af" textAnchor="end"
              style={{ fontFamily: 'var(--bx-font-mono)' }}>{t >= 1000 ? (t/1000).toFixed(1) + 'k' : t}</text>
          </g>
        ))}
        {data.map((row, i) => {
          let acc = 0;
          return (
            <g key={i} onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}>
              {stacks.map(st => {
                const v = row[st.key] || 0;
                const yT = y(acc + v);
                const yB = y(acc);
                acc += v;
                return (
                  <rect key={st.key} x={x(i) - barW/2} y={yT} width={barW} height={Math.max(0, yB - yT)}
                    fill={st.color} stroke="#fff" strokeWidth="0.5"
                    opacity={hover === null || hover === i ? 1 : 0.55}/>
                );
              })}
              <text x={x(i)} y={height - 14} fontSize="10" fill="#99a1af" textAnchor="middle"
                style={{ fontFamily: 'var(--bx-font-sans)' }}>{row[xKey]}</text>
              <text x={x(i)} y={height - 2} fontSize="10" fill="#4a4a4a" textAnchor="middle"
                style={{ fontFamily: 'var(--bx-font-mono)', fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>
                {totals[i].toLocaleString('en-US')}
              </text>
            </g>
          );
        })}
      </svg>
      {hover !== null && (
        <div style={{
          position: 'absolute', left: Math.min(w - 200, Math.max(0, x(hover) - 90)), top: 6,
          background: '#fff', border: '1px solid var(--bx-border-muted)',
          borderRadius: 8, padding: '8px 10px', boxShadow: 'var(--bx-shadow-pop)',
          pointerEvents: 'none', minWidth: 180, fontSize: 11.5,
        }}>
          <div style={{ fontWeight: 600, marginBottom: 4, color: 'var(--bx-text-heading)' }}>{data[hover][xKey]}</div>
          {stacks.map(s => (
            <div key={s.key} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ width: 8, height: 8, background: s.color, borderRadius: 2 }}></span>
              <span style={{ flex: 1 }}>{s.label}</span>
              <span style={{ fontFamily: 'var(--bx-font-mono)', fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>{(data[hover][s.key] || 0).toLocaleString('en-US')}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function ChartLegend({ items, style }) {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 14, fontSize: 11.5, color: 'var(--bx-text-body)', ...style }}>
      {items.map(it => (
        <div key={it.label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{
            width: 12, height: it.dashed ? 0 : 8, borderRadius: it.dashed ? 0 : 2,
            background: it.color, borderTop: it.dashed ? `2px dashed ${it.color}` : 'none',
          }}></span>
          <span>{it.label}</span>
        </div>
      ))}
    </div>
  );
}

// Coverage area (stepped) chart
function CoverageChart({ data, height = 180 }) {
  const ref = React.useRef(null);
  const w = useChartSize(ref);
  const padding = { top: 12, right: 12, bottom: 24, left: 36 };
  const innerW = w - padding.left - padding.right;
  const innerH = height - padding.top - padding.bottom;

  const max = Math.max(...data.map(d => d.total), 1);
  const ticks = niceTicks(max, 4);
  const top = ticks[ticks.length - 1] || 1;
  const x = (h) => padding.left + (h / 24) * innerW;
  const y = (v) => padding.top + innerH - (v / top) * innerH;

  function buildArea(stackKey) {
    let d = '';
    let acc = 0;
    const points = [];
    data.forEach((row, i) => {
      const layers = ['morning','afternoon','night'];
      let below = 0;
      for (const k of layers) {
        if (k === stackKey) break;
        below += row[k];
      }
      const top = below + row[stackKey];
      points.push({ h: i, below, top });
    });
    d += 'M' + x(0) + ' ' + y(points[0].top);
    for (let i = 1; i < points.length; i++) {
      d += ' L' + x(i) + ' ' + y(points[i-1].top);
      d += ' L' + x(i) + ' ' + y(points[i].top);
    }
    d += ' L' + x(24) + ' ' + y(points[points.length-1].top);
    // back along below
    d += ' L' + x(24) + ' ' + y(points[points.length-1].below);
    for (let i = points.length - 1; i >= 1; i--) {
      d += ' L' + x(i) + ' ' + y(points[i].below);
      d += ' L' + x(i) + ' ' + y(points[i-1].below);
    }
    d += ' L' + x(0) + ' ' + y(points[0].below) + ' Z';
    return d;
  }
  const colors = { morning: '#0b43ea', afternoon: '#4f7dff', night: '#a4b5ff' };

  return (
    <div ref={ref} style={{ width: '100%' }}>
      <svg width={w} height={height} style={{ display: 'block' }}>
        {ticks.map(t => (
          <g key={t}>
            <line x1={padding.left} x2={w - padding.right} y1={y(t)} y2={y(t)}
              stroke="#ececec" strokeDasharray={t === 0 ? '0' : '3 3'}/>
            <text x={padding.left - 6} y={y(t)+4} fontSize="10" fill="#99a1af" textAnchor="end"
              style={{ fontFamily: 'var(--bx-font-mono)' }}>{t}</text>
          </g>
        ))}
        {/* areas */}
        <path d={buildArea('morning')}   fill={colors.morning}   opacity="0.85"/>
        <path d={buildArea('afternoon')} fill={colors.afternoon} opacity="0.85"/>
        <path d={buildArea('night')}     fill={colors.night}     opacity="0.85"/>
        {/* x axis */}
        {[0,4,8,12,16,20,24].map(h => (
          <text key={h} x={x(h)} y={height - 6} fontSize="10" fill="#99a1af" textAnchor="middle"
            style={{ fontFamily: 'var(--bx-font-mono)' }}>{String(h).padStart(2,'0')}h</text>
        ))}
      </svg>
    </div>
  );
}

// Sparkline (small inline)
function Sparkline({ data, color = '#0b43ea', width = 80, height = 22 }) {
  const max = Math.max(...data), min = Math.min(...data);
  const range = max - min || 1;
  const points = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / range) * (height - 4) - 2;
    return x + ',' + y;
  }).join(' ');
  return (
    <svg width={width} height={height} style={{ display: 'block' }}>
      <polyline fill="none" stroke={color} strokeWidth="1.5" points={points} strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}

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