// Sparkline + TrendChart — hand-rolled SVG (matches design exactly).
// Both components read the active SERIES from React context.

const SeriesContext = React.createContext(null);
window.SeriesContext = SeriesContext;

function buildPath(vals, x, y) {
  return vals.map((v, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(v)}`).join(' ');
}
function buildAreaPath(top, bot, x, y) {
  let d = '';
  top.forEach((v, i) => { d += `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(v)} `; });
  for (let i = bot.length - 1; i >= 0; i--) d += `L ${x(i)} ${y(bot[i])} `;
  return d + 'Z';
}

function Sparkline({
  series, days = 14, width = 320, height = 60,
  showTarget = false, showLast = false,
  lastLabel = null, color, padX = 0, padY = 8,
  targetLabel = null, annotation = null, fullWidth = false,
}) {
  const theme = window.HC_THEME.useHCTheme();
  const SERIES = React.useContext(SeriesContext);
  const s = SERIES && SERIES[series];
  if (!s) return null;
  const c = color || s.color;
  const ch = theme.chart;
  const pal = theme.palette;

  const raw = s.raw.slice(-days);
  const avg = s.avg.slice(-days);
  const std = s.std.slice(-days);

  // Auto-fit Y to the trend + raw points only. The ±1σ band is excluded
  // from the domain calc so the line uses the full vertical space — any
  // band edges that extend past the card are clipped softly behind.
  let allVals = [...avg, ...raw];
  if (s.target != null && showTarget) allVals.push(s.target);
  let min = Math.min(...allVals), max = Math.max(...allVals);
  const range = max - min || 1;
  min -= range * 0.08; max += range * 0.08;
  if (s.invert) { [min, max] = [max, min]; }

  const x = (i) => padX + (i / (days - 1)) * (width - 2 * padX);
  const y = (v) => padY + ((max - v) / (max - min)) * (height - 2 * padY);

  const upper = avg.map((v, i) => v + std[i]);
  const lower = avg.map((v, i) => v - std[i]);
  const lastY = y(avg[avg.length - 1]);
  const clipId = `sp-clip-${series}-${width}-${height}`;

  return (
    <svg width={fullWidth ? '100%' : width} height={height} viewBox={`0 0 ${width} ${height}`}
         preserveAspectRatio="none" style={{ display: 'block' }}>
      <defs>
        <clipPath id={clipId}>
          <rect x="0" y="0" width={width} height={height} />
        </clipPath>
      </defs>
      <g clipPath={`url(#${clipId})`}>
      {showTarget && s.target != null && (
        <>
          <line x1={padX} x2={width - padX} y1={y(s.target)} y2={y(s.target)}
                stroke={pal.targetLine} strokeWidth="1" strokeDasharray="3 3" opacity="0.45" />
          {targetLabel && (
            <text x={padX + 4} y={y(s.target) - 4} fontSize="9" fill={pal.targetLine} opacity="0.75"
                  fontFamily="DM Mono, monospace">{targetLabel}</text>
          )}
        </>
      )}

      {ch.showBand && (
        <path d={buildAreaPath(upper, lower, x, y)} fill={c} opacity={ch.bandOpacity} />
      )}

      {ch.showRaw && (
        <path d={buildPath(raw, x, y)} fill="none" stroke={c} strokeWidth="0.8" opacity={ch.rawOpacity} />
      )}

      <path d={buildPath(avg, x, y)} fill="none" stroke={c} strokeWidth={ch.lineWidth}
            strokeLinecap="round" strokeLinejoin="round" opacity={ch.trendOpacity} />

      {ch.showRaw && raw.map((v, i) => (
        <circle key={i} cx={x(i)} cy={y(v)} r={ch.dotR} fill={c} opacity={ch.rawOpacity} />
      ))}

      {annotation && (
        <>
          <line x1={x(annotation.idx)} x2={x(annotation.idx)} y1={padY} y2={height - padY}
                stroke={pal.warning} strokeWidth="0.8" strokeDasharray="2 2" opacity="0.5" />
          <text x={x(annotation.idx) + 3} y={padY + 8} fontSize="9" fill={pal.warning} opacity="0.75"
                fontFamily="DM Mono, monospace">{annotation.label}</text>
        </>
      )}

      {showLast ? (
        <>
          <circle cx={x(days - 1)} cy={lastY} r="3" fill={c} />
          {lastLabel && (
            <text x={x(days - 1) - 4} y={lastY + 14} fontSize="10" fill={c}
                  fontFamily="DM Mono, monospace" textAnchor="end">{lastLabel}</text>
          )}
        </>
      ) : ch.dotR > 0 && (
        <circle cx={x(days - 1)} cy={lastY} r="1.8" fill={c} />
      )}
      </g>
    </svg>
  );
}

function TrendChart({
  series, width = 358, height = 160, refLine, refLabel,
  invert = false, yFormat, showVolBand = false, phases = [],
  annotations = [], range = 'full', windowDays = 60,
}) {
  const theme = window.HC_THEME.useHCTheme();
  const pal = theme.palette;
  const ch = theme.chart;
  const SERIES = React.useContext(SeriesContext);
  const s = SERIES && SERIES[series];
  if (!s) return null;

  // Window: 4w shows 28 days, full shows windowDays (typically ~150).
  const total = s.raw.length;
  const days = range === '4w' ? Math.min(28, total) : Math.min(windowDays, total);
  const offset = total - days; // index offset from full-series to window

  const raw = s.raw.slice(-days);
  const ewma = s.avg.slice(-days);
  // 14-day SMA computed across the full series, then sliced.
  const ma14 = s.raw.map((_, i) => {
    const start = Math.max(0, i - 13);
    const slice = s.raw.slice(start, i + 1);
    return slice.reduce((a, b) => a + b, 0) / slice.length;
  }).slice(-days);
  const std = s.std.slice(-days);

  let allVals = [...raw, ...ewma, ...ma14];
  if (showVolBand || ch.showBand) {
    allVals = allVals.concat(
      ewma.map((v, i) => v + std[i]),
      ewma.map((v, i) => v - std[i]),
    );
  }
  if (refLine != null) allVals.push(refLine);
  let min = Math.min(...allVals), max = Math.max(...allVals);
  const r = max - min || 1;
  min -= r * 0.1; max += r * 0.1;
  if (invert) [min, max] = [max, min];

  const padL = 32, padR = 12, padT = 14, padB = 22;
  const innerW = width - padL - padR;
  const innerH = height - padT - padB;
  const x = (i) => padL + (i / Math.max(1, days - 1)) * innerW;
  const y = (v) => padT + ((max - v) / (max - min)) * innerH;

  const ticks = [];
  for (let t = 0; t < 4; t++) {
    const frac = t / 3;
    const v = invert ? min + (max - min) * (1 - frac) : min + (max - min) * frac;
    ticks.push({ v, y: padT + innerH * (1 - frac) });
  }

  const upper = ewma.map((v, i) => v + std[i]);
  const lower = ewma.map((v, i) => v - std[i]);

  return (
    <svg width="100%" height={height} viewBox={`0 0 ${width} ${height}`}
         preserveAspectRatio="none" style={{ display: 'block' }}>
      {phases.map((p, i) => {
        const [a, b] = p.range;
        const a2 = Math.max(0, a - offset);
        const b2 = Math.max(0, b - offset);
        if (b2 <= 0 || a2 >= days) return null;
        return (
          <rect key={i}
                x={x(a2)} y={padT}
                width={x(Math.min(b2, days - 1)) - x(a2)} height={innerH}
                fill={p.color} />
        );
      })}

      {ticks.map((t, i) => (
        <line key={i} x1={padL} x2={width - padR} y1={t.y} y2={t.y}
              stroke={pal.grid} strokeWidth="1" />
      ))}

      {ticks.map((t, i) => (
        <text key={i} x={padL - 6} y={t.y + 3} fontSize="9" fill={pal.text3}
              fontFamily="DM Mono, monospace" textAnchor="end">
          {yFormat ? yFormat(t.v) : t.v.toFixed(t.v < 10 ? 1 : 0)}
        </text>
      ))}

      {refLine != null && (
        <>
          <line x1={padL} x2={width - padR} y1={y(refLine)} y2={y(refLine)}
                stroke={pal.targetLine} strokeWidth="1" strokeDasharray="3 3" opacity="0.5" />
          {refLabel && (
            <text x={width - padR - 4} y={y(refLine) - 4} fontSize="9" fill={pal.targetLine}
                  fontFamily="DM Mono, monospace" textAnchor="end" opacity="0.8">{refLabel}</text>
          )}
        </>
      )}

      {(showVolBand || theme.chartKey === 'telemetry') && (
        <path d={buildAreaPath(upper, lower, x, y)} fill={s.color} opacity="0.08" />
      )}

      {/* Raw area fill + line. Present in signal & telemetry. */}
      {!showVolBand && theme.chartKey !== 'whisper' && (
        <>
          <path d={`${buildPath(raw, x, y)} L ${x(days - 1)} ${y(min)} L ${x(0)} ${y(min)} Z`}
                fill={s.color} opacity={theme.chartKey === 'telemetry' ? 0.1 : 0.06} />
          <path d={buildPath(raw, x, y)} fill="none" stroke={s.color}
                strokeWidth={theme.chartKey === 'telemetry' ? 1 : 0.8}
                opacity={theme.chartKey === 'telemetry' ? 0.5 : 0.3} />
        </>
      )}

      {/* 14-day MA dashed — only on signal & telemetry. */}
      {theme.chartKey !== 'whisper' && (
        <path d={buildPath(ma14, x, y)} fill="none" stroke={s.color} strokeWidth="1"
              strokeDasharray="3 2" opacity="0.55" />
      )}

      {/* EWMA — primary trend line. */}
      <path d={buildPath(ewma, x, y)} fill="none" stroke={s.color}
            strokeWidth={theme.chartKey === 'telemetry' ? 2.4 : theme.chartKey === 'whisper' ? 1.6 : 2}
            strokeLinecap="round" strokeLinejoin="round" />

      {theme.chartKey === 'telemetry' && raw.map((v, i) => (
        <circle key={i} cx={x(i)} cy={y(v)} r="1.4" fill={s.color} opacity="0.55" />
      ))}

      {/* User-logged event markers from /api/events. */}
      {annotations.map((a, i) => {
        const idx = a.idx - offset;
        if (idx < 0 || idx >= days) return null;
        return (
          <g key={i}>
            <line x1={x(idx)} x2={x(idx)} y1={padT} y2={padT + innerH}
                  stroke={pal.warning} strokeWidth="0.8" strokeDasharray="2 2" opacity="0.55" />
            <text x={x(idx) + 3} y={padT + 9} fontSize="9" fill={pal.warning}
                  fontFamily="DM Mono, monospace" opacity="0.85">{a.label}</text>
          </g>
        );
      })}

      {/* X-axis date labels at start / middle / end. Uses the actual date from
          the days array — the design hardcoded May 10 because it was a mock. */}
      <DateTicks days={days} offset={offset} x={x} height={height} pal={pal} />
    </svg>
  );
}

function DateTicks({ days, offset, x, height, pal }) {
  const SERIES = React.useContext(SeriesContext);
  const dates = window.HC_TREND_DATES || null; // injected by TrendsTab
  const positions = [0, Math.floor(days / 2), days - 1];
  return positions.map((i) => {
    let label = '';
    if (dates) {
      const isoIdx = offset + i;
      const iso = dates[isoIdx];
      if (iso) {
        const dt = new Date(iso + 'T00:00:00');
        label = `${['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][dt.getMonth()]} ${dt.getDate()}`;
      }
    }
    return (
      <text key={i} x={x(i)} y={height - 6} fontSize="9" fill={pal.text3}
            fontFamily="DM Mono, monospace"
            textAnchor={i === 0 ? 'start' : i === days - 1 ? 'end' : 'middle'}>{label}</text>
    );
  });
}

window.Sparkline = Sparkline;
window.TrendChart = TrendChart;
