// charts.jsx — SVG sparkline + annotated full chart

const { useMemo } = React;

function MiniChart({ series, pattern, dir, w = 280, h = 90, animated = false }) {
  const min = Math.min(...series);
  const max = Math.max(...series);
  const pad = (max - min) * 0.12 || 1;
  const yMin = min - pad;
  const yMax = max + pad;
  const sx = (i) => (i / (series.length - 1)) * (w - 4) + 2;
  const sy = (v) => h - ((v - yMin) / (yMax - yMin)) * (h - 4) - 2;
  const pts = series.map((v, i) => `${sx(i).toFixed(2)},${sy(v).toFixed(2)}`).join(' ');
  const color = dir === 'BUY' ? '#39ff7a' : '#ff3b3b';
  const fillColor = dir === 'BUY' ? 'rgba(57,255,122,0.15)' : 'rgba(255,59,59,0.15)';
  const areaPath = `M2,${h - 2} L${pts.replace(/ /g, ' L')} L${(w - 2).toFixed(2)},${h - 2} Z`;

  // Pattern-specific annotations
  const annotations = useMemo(() => annotatePattern(pattern, series, sx, sy, w, h), [pattern, series, w, h]);

  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ display: 'block' }}>
      <defs>
        <linearGradient id={`g-${pattern}-${dir}-${w}`} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.35" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      {/* grid */}
      {[0.25, 0.5, 0.75].map(p => (
        <line key={p} x1="0" x2={w} y1={h * p} y2={h * p} stroke="rgba(57,255,122,0.08)" strokeDasharray="2 4" />
      ))}
      <path d={areaPath} fill={`url(#g-${pattern}-${dir}-${w})`} />
      <polyline
        points={pts}
        fill="none"
        stroke={color}
        strokeWidth="1.4"
        strokeLinejoin="round"
        strokeLinecap="round"
        style={animated ? { strokeDasharray: 600, strokeDashoffset: 0, animation: 'drawline 1.2s ease-out' } : {}}
      />
      {annotations}
      {/* last point pulse */}
      <circle cx={sx(series.length - 1)} cy={sy(series[series.length - 1])} r="2.5" fill={color}>
        <animate attributeName="r" values="2.5;5;2.5" dur="1.6s" repeatCount="indefinite" />
        <animate attributeName="opacity" values="1;0.4;1" dur="1.6s" repeatCount="indefinite" />
      </circle>
    </svg>
  );
}

function annotatePattern(pattern, series, sx, sy, w, h) {
  const labelStyle = {
    fontFamily: 'JetBrains Mono, monospace',
    fontSize: 8,
    fill: 'rgba(57,255,122,0.85)',
    letterSpacing: '0.05em',
  };

  const findExtrema = () => {
    const peaks = [];
    const troughs = [];
    for (let i = 2; i < series.length - 2; i++) {
      if (series[i] > series[i-1] && series[i] > series[i-2] && series[i] > series[i+1] && series[i] > series[i+2]) peaks.push(i);
      if (series[i] < series[i-1] && series[i] < series[i-2] && series[i] < series[i+1] && series[i] < series[i+2]) troughs.push(i);
    }
    return { peaks, troughs };
  };

  switch (pattern) {
    case 'HEAD_SHOULDERS': {
      const { peaks } = findExtrema();
      if (peaks.length < 3) return null;
      // pick three peaks closest to expected positions
      const targets = [series.length * 0.25, series.length * 0.5, series.length * 0.75];
      const chosen = targets.map(t => peaks.reduce((best, p) => Math.abs(p - t) < Math.abs(best - t) ? p : best, peaks[0]));
      const [ls, head, rs] = chosen;
      const neckline = (series[ls] + series[rs]) / 2 * 0.97;
      return (
        <g>
          <line x1={sx(ls)} y1={sy(neckline)} x2={sx(rs)} y2={sy(neckline)} stroke="rgba(255,59,59,0.6)" strokeDasharray="3 3" strokeWidth="1" />
          {[ls, head, rs].map((p, i) => (
            <g key={i}>
              <circle cx={sx(p)} cy={sy(series[p])} r="3" fill="none" stroke="rgba(255,59,59,0.9)" strokeWidth="1" />
              <text x={sx(p)} y={sy(series[p]) - 6} textAnchor="middle" {...labelStyle} fill="rgba(255,59,59,0.85)">
                {i === 1 ? 'H' : (i === 0 ? 'LS' : 'RS')}
              </text>
            </g>
          ))}
        </g>
      );
    }
    case 'INV_HEAD_SHOULDERS': {
      const { troughs } = findExtrema();
      if (troughs.length < 3) return null;
      const targets = [series.length * 0.25, series.length * 0.5, series.length * 0.75];
      const chosen = targets.map(t => troughs.reduce((best, p) => Math.abs(p - t) < Math.abs(best - t) ? p : best, troughs[0]));
      const [ls, head, rs] = chosen;
      const neckline = (series[ls] + series[rs]) / 2 * 1.03;
      return (
        <g>
          <line x1={sx(ls)} y1={sy(neckline)} x2={sx(rs)} y2={sy(neckline)} stroke="rgba(57,255,122,0.6)" strokeDasharray="3 3" strokeWidth="1" />
          {[ls, head, rs].map((p, i) => (
            <g key={i}>
              <circle cx={sx(p)} cy={sy(series[p])} r="3" fill="none" stroke="rgba(57,255,122,0.9)" strokeWidth="1" />
              <text x={sx(p)} y={sy(series[p]) + 14} textAnchor="middle" {...labelStyle}>
                {i === 1 ? 'H' : (i === 0 ? 'LS' : 'RS')}
              </text>
            </g>
          ))}
        </g>
      );
    }
    case 'DOUBLE_TOP':
    case 'DOUBLE_BOTTOM': {
      const isTop = pattern === 'DOUBLE_TOP';
      const { peaks, troughs } = findExtrema();
      const list = isTop ? peaks : troughs;
      if (list.length < 2) return null;
      const t1 = list.reduce((b, p) => Math.abs(p - series.length * 0.3) < Math.abs(b - series.length * 0.3) ? p : b, list[0]);
      const t2 = list.reduce((b, p) => Math.abs(p - series.length * 0.65) < Math.abs(b - series.length * 0.65) ? p : b, list[0]);
      const lvl = (series[t1] + series[t2]) / 2;
      const c = isTop ? 'rgba(255,59,59,0.85)' : 'rgba(57,255,122,0.85)';
      return (
        <g>
          <line x1={sx(t1)} y1={sy(lvl)} x2={sx(t2)} y2={sy(lvl)} stroke={c} strokeDasharray="3 3" strokeWidth="1" />
          {[t1, t2].map((p, i) => (
            <g key={i}>
              <circle cx={sx(p)} cy={sy(series[p])} r="3" fill="none" stroke={c} strokeWidth="1" />
              <text x={sx(p)} y={isTop ? sy(series[p]) - 6 : sy(series[p]) + 14} textAnchor="middle" {...labelStyle} fill={c}>
                {i === 0 ? (isTop ? 'T1' : 'B1') : (isTop ? 'T2' : 'B2')}
              </text>
            </g>
          ))}
        </g>
      );
    }
    case 'TRIPLE_TOP':
    case 'TRIPLE_BOTTOM': {
      const isTop = pattern === 'TRIPLE_TOP';
      const { peaks, troughs } = findExtrema();
      const list = isTop ? peaks : troughs;
      if (list.length < 3) return null;
      const targets = [series.length * 0.2, series.length * 0.45, series.length * 0.7];
      const chosen = targets.map(t => list.reduce((b, p) => Math.abs(p - t) < Math.abs(b - t) ? p : b, list[0]));
      const lvl = chosen.reduce((s, p) => s + series[p], 0) / 3;
      const c = isTop ? 'rgba(255,59,59,0.85)' : 'rgba(57,255,122,0.85)';
      return (
        <g>
          <line x1={sx(chosen[0])} y1={sy(lvl)} x2={sx(chosen[2])} y2={sy(lvl)} stroke={c} strokeDasharray="3 3" strokeWidth="1" />
          {chosen.map((p, i) => (
            <g key={i}>
              <circle cx={sx(p)} cy={sy(series[p])} r="3" fill="none" stroke={c} strokeWidth="1" />
              <text x={sx(p)} y={isTop ? sy(series[p]) - 6 : sy(series[p]) + 14} textAnchor="middle" {...labelStyle} fill={c}>
                {(isTop ? 'T' : 'B') + (i + 1)}
              </text>
            </g>
          ))}
          {/* breakout marker */}
          <line x1={sx(series.length - 1)} y1={sy(lvl)} x2={sx(series.length - 1)} y2={sy(series[series.length - 1])}
            stroke={c} strokeWidth="1" strokeDasharray="1 2" />
        </g>
      );
    }
    case 'SYM_TRIANGLE': {
      const c = 'rgba(57,255,122,0.7)';
      const startIdx = 2;
      const endIdx = Math.floor(series.length * 0.85);
      const mid = (Math.max(...series) + Math.min(...series)) / 2;
      return (
        <g>
          <line x1={sx(startIdx)} y1={sy(series[startIdx] * 1.04)} x2={sx(endIdx)} y2={sy(mid * 1.005)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(startIdx)} y1={sy(series[startIdx] * 0.96)} x2={sx(endIdx)} y2={sy(mid * 0.995)} stroke={c} strokeDasharray="3 3" />
          <text x={sx(endIdx)} y={sy(mid) - 4} textAnchor="end" {...labelStyle}>APEX</text>
        </g>
      );
    }
    case 'BULL_PENNANT':
    case 'BEAR_PENNANT': {
      const isBull = pattern === 'BULL_PENNANT';
      const c = isBull ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      const poleStart = 2;
      const penStart = Math.floor(series.length * 0.4);
      const penEnd = Math.floor(series.length * 0.85);
      // pole line
      const apex = (series[penStart] + series[penEnd]) / 2;
      return (
        <g>
          <line x1={sx(poleStart)} y1={sy(series[poleStart])} x2={sx(penStart)} y2={sy(series[penStart])} stroke={c} strokeWidth="1.2" />
          <text x={sx((poleStart + penStart) / 2)} y={sy((series[poleStart] + series[penStart]) / 2) + (isBull ? 14 : -4)} textAnchor="middle" {...labelStyle} fill={c}>POLE</text>
          <line x1={sx(penStart)} y1={sy(series[penStart] * 1.025)} x2={sx(penEnd)} y2={sy(apex)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(penStart)} y1={sy(series[penStart] * 0.975)} x2={sx(penEnd)} y2={sy(apex)} stroke={c} strokeDasharray="3 3" />
        </g>
      );
    }
    case 'RECT_TOP':
    case 'RECT_BOTTOM': {
      const isTop = pattern === 'RECT_TOP';
      const c = isTop ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      const startIdx = Math.floor(series.length * 0.15);
      const endIdx = Math.floor(series.length * 0.85);
      const slice = series.slice(startIdx, endIdx);
      const top = Math.max(...slice);
      const bot = Math.min(...slice);
      return (
        <g>
          <rect x={sx(startIdx)} y={sy(top)} width={sx(endIdx) - sx(startIdx)} height={sy(bot) - sy(top)}
            fill={isTop ? 'rgba(57,255,122,0.05)' : 'rgba(255,59,59,0.05)'} stroke={c} strokeDasharray="3 3" strokeWidth="1" />
          <text x={sx(endIdx) - 4} y={sy(top) - 3} textAnchor="end" {...labelStyle} fill={c}>R</text>
          <text x={sx(endIdx) - 4} y={sy(bot) + 9} textAnchor="end" {...labelStyle} fill={c}>S</text>
        </g>
      );
    }
    case 'GOLDEN_CROSS':
    case 'DEATH_CROSS': {
      const isGold = pattern === 'GOLDEN_CROSS';
      const c = isGold ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      // simple MA approximation
      const ma = (window) => series.map((_, i) => {
        const start = Math.max(0, i - window);
        const slice = series.slice(start, i + 1);
        return slice.reduce((a, b) => a + b, 0) / slice.length;
      });
      const ma50 = ma(8);
      const ma200 = ma(20);
      const path = (a) => a.map((v, i) => `${sx(i).toFixed(1)},${sy(v).toFixed(1)}`).join(' ');
      // find cross point
      let cross = -1;
      for (let i = 1; i < series.length; i++) {
        if (isGold && ma50[i] > ma200[i] && ma50[i-1] <= ma200[i-1]) { cross = i; break; }
        if (!isGold && ma50[i] < ma200[i] && ma50[i-1] >= ma200[i-1]) { cross = i; break; }
      }
      return (
        <g>
          <polyline points={path(ma50)} fill="none" stroke={c} strokeWidth="1" strokeDasharray="4 2" opacity="0.7" />
          <polyline points={path(ma200)} fill="none" stroke="rgba(202,255,217,0.5)" strokeWidth="1" strokeDasharray="2 3" />
          {cross > 0 && (
            <g>
              <circle cx={sx(cross)} cy={sy(ma50[cross])} r="4" fill="none" stroke={c} strokeWidth="1.5" />
              <text x={sx(cross)} y={sy(ma50[cross]) + (isGold ? -8 : 14)} textAnchor="middle" {...labelStyle} fill={c}>✕</text>
            </g>
          )}
        </g>
      );
    }
    case 'CUP_HANDLE': {
      const min = series.indexOf(Math.min(...series.slice(0, Math.floor(series.length * 0.7))));
      const rim = Math.max(series[0], series[Math.floor(series.length * 0.7)]);
      return (
        <g>
          <line x1="2" y1={sy(rim)} x2={w - 2} y2={sy(rim)} stroke="rgba(57,255,122,0.6)" strokeDasharray="3 3" strokeWidth="1" />
          <text x={w - 4} y={sy(rim) - 3} textAnchor="end" {...labelStyle}>RIM</text>
          <text x={sx(min)} y={sy(series[min]) + 12} textAnchor="middle" {...labelStyle}>CUP</text>
        </g>
      );
    }
    case 'ASC_TRIANGLE':
    case 'DESC_TRIANGLE': {
      const isAsc = pattern === 'ASC_TRIANGLE';
      const peakLvl = Math.max(...series.slice(2, Math.floor(series.length * 0.85)));
      const lows = [];
      for (let i = 5; i < series.length * 0.85; i += 8) lows.push(i);
      const c = isAsc ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      return (
        <g>
          {isAsc ? (
            <>
              <line x1={sx(2)} y1={sy(peakLvl)} x2={sx(series.length * 0.85)} y2={sy(peakLvl)} stroke={c} strokeDasharray="3 3" />
              <line x1={sx(2)} y1={sy(series[2] * 0.97)} x2={sx(series.length * 0.85)} y2={sy(peakLvl * 0.99)} stroke={c} strokeDasharray="3 3" />
            </>
          ) : (
            <>
              <line x1={sx(2)} y1={sy(peakLvl * 1.01)} x2={sx(series.length * 0.85)} y2={sy(peakLvl * 0.97)} stroke={c} strokeDasharray="3 3" />
              <line x1={sx(2)} y1={sy(Math.min(...series))} x2={sx(series.length * 0.85)} y2={sy(Math.min(...series))} stroke={c} strokeDasharray="3 3" />
            </>
          )}
        </g>
      );
    }
    case 'FALLING_WEDGE':
    case 'RISING_WEDGE': {
      const isFall = pattern === 'FALLING_WEDGE';
      const c = isFall ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      return (
        <g>
          <line x1={sx(2)} y1={sy(series[2] * (isFall ? 1.04 : 1.02))} x2={sx(series.length * 0.85)} y2={sy(series[Math.floor(series.length * 0.85)] * 1.01)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(2)} y1={sy(series[2] * (isFall ? 0.96 : 0.98))} x2={sx(series.length * 0.85)} y2={sy(series[Math.floor(series.length * 0.85)] * 0.99)} stroke={c} strokeDasharray="3 3" />
        </g>
      );
    }
    case 'BULL_FLAG':
    case 'BEAR_FLAG': {
      const isBull = pattern === 'BULL_FLAG';
      const c = isBull ? 'rgba(57,255,122,0.7)' : 'rgba(255,59,59,0.7)';
      const poleStart = 2;
      const flagStart = Math.floor(series.length * 0.4);
      const flagEnd = Math.floor(series.length * 0.85);
      const flagTop = Math.max(...series.slice(flagStart, flagEnd)) * 1.005;
      const flagBot = Math.min(...series.slice(flagStart, flagEnd)) * 0.995;
      return (
        <g>
          {/* pole */}
          <line x1={sx(poleStart)} y1={sy(series[poleStart])} x2={sx(flagStart)} y2={sy(series[flagStart])} stroke={c} strokeWidth="1.4" />
          <text x={sx((poleStart + flagStart) / 2)} y={sy((series[poleStart] + series[flagStart]) / 2) + (isBull ? 14 : -4)} textAnchor="middle" {...labelStyle} fill={c}>POLE</text>
          {/* flag */}
          <line x1={sx(flagStart)} y1={sy(flagTop)} x2={sx(flagEnd)} y2={sy(flagTop)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(flagStart)} y1={sy(flagBot)} x2={sx(flagEnd)} y2={sy(flagBot)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(flagStart)} y1={sy(flagTop)} x2={sx(flagStart)} y2={sy(flagBot)} stroke={c} strokeDasharray="3 3" />
          <line x1={sx(flagEnd)} y1={sy(flagTop)} x2={sx(flagEnd)} y2={sy(flagBot)} stroke={c} strokeDasharray="3 3" />
          <text x={sx((flagStart + flagEnd) / 2)} y={sy(flagTop) - 3} textAnchor="middle" {...labelStyle} fill={c}>FLAG</text>
        </g>
      );
    }
    case 'VOL_BREAKOUT':
    case 'RESISTANCE_BREAK': {
      const lvl = Math.max(...series.slice(0, Math.floor(series.length * 0.8))) * 1.005;
      return (
        <g>
          <line x1="2" y1={sy(lvl)} x2={w - 2} y2={sy(lvl)} stroke="rgba(57,255,122,0.7)" strokeDasharray="3 3" />
          <text x={w - 4} y={sy(lvl) - 3} textAnchor="end" {...labelStyle}>R</text>
        </g>
      );
    }
    case 'SUPPORT_BREAK': {
      const lvl = Math.min(...series.slice(0, Math.floor(series.length * 0.8))) * 0.995;
      return (
        <g>
          <line x1="2" y1={sy(lvl)} x2={w - 2} y2={sy(lvl)} stroke="rgba(255,59,59,0.7)" strokeDasharray="3 3" />
          <text x={w - 4} y={sy(lvl) + 9} textAnchor="end" {...labelStyle} fill="rgba(255,59,59,0.85)">S</text>
        </g>
      );
    }
    default: return null;
  }
}

function VolumeBars({ volume, w = 280, h = 28 }) {
  const max = Math.max(...volume);
  const avg30 = volume.slice(0, 30).reduce((a,b) => a + b, 0) / 30;
  const bw = (w - 4) / volume.length;
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ display: 'block' }}>
      <line x1="2" x2={w - 2} y1={h - (avg30 / max) * (h - 2)} y2={h - (avg30 / max) * (h - 2)}
            stroke="rgba(57,255,122,0.4)" strokeDasharray="2 3" strokeWidth="1" />
      {volume.map((v, i) => {
        const bh = (v / max) * (h - 2);
        const isSpike = v > avg30 * 1.5;
        return (
          <rect
            key={i}
            x={i * bw + 2}
            y={h - bh}
            width={Math.max(1, bw - 0.6)}
            height={bh}
            fill={isSpike ? 'rgba(57,255,122,0.85)' : 'rgba(57,255,122,0.25)'}
          />
        );
      })}
    </svg>
  );
}

window.MiniChart = MiniChart;
window.VolumeBars = VolumeBars;
window.annotatePattern = annotatePattern;
