// Sparkline chart with timeframe selector, time axis, and floating hover bubble
function Sparkline({ series, loading, from, to, timeframe, onTimeframeChange, histAvailable = true }) {
  const [hoverIdx, setHoverIdx] = React.useState(null);
  const [hoverPx, setHoverPx] = React.useState(null); // {x,y} in container px
  const svgRef = React.useRef(null);
  const wrapRef = React.useRef(null);
  const pathRef = React.useRef(null);
  const areaRef = React.useRef(null);

  const W = 760, H = 180, P = 16;

  const { pathD, areaD, points, min, max } = React.useMemo(() => {
    if (!series || series.length === 0) {
      return { pathD: "", areaD: "", points: [], min: 0, max: 0 };
    }
    const values = series.map(d => d.value);
    const min = Math.min(...values);
    const max = Math.max(...values);
    const range = max - min || 1;
    const n = series.length;
    const pts = series.map((d, i) => {
      const x = P + (i / (n - 1)) * (W - 2 * P);
      const y = P + (1 - (d.value - min) / range) * (H - 2 * P);
      return { x, y, ...d };
    });
    // Smooth Catmull-Rom cubic spline
    let path = `M${pts[0].x.toFixed(2)} ${pts[0].y.toFixed(2)}`;
    for (let i = 0; i < pts.length - 1; i++) {
      const p0 = pts[i - 1] || pts[i];
      const p1 = pts[i];
      const p2 = pts[i + 1];
      const p3 = pts[i + 2] || p2;
      const cp1x = p1.x + (p2.x - p0.x) / 6;
      const cp1y = p1.y + (p2.y - p0.y) / 6;
      const cp2x = p2.x - (p3.x - p1.x) / 6;
      const cp2y = p2.y - (p3.y - p1.y) / 6;
      path += ` C${cp1x.toFixed(2)} ${cp1y.toFixed(2)}, ${cp2x.toFixed(2)} ${cp2y.toFixed(2)}, ${p2.x.toFixed(2)} ${p2.y.toFixed(2)}`;
    }
    const area = path + ` L${pts[pts.length - 1].x.toFixed(2)} ${H - P} L${pts[0].x.toFixed(2)} ${H - P} Z`;
    return { pathD: path, areaD: area, points: pts, min, max };
  }, [series]);

  // Draw-in animation on pair/timeframe change
  const animKey = `${from}-${to}-${timeframe}-${series?.length || 0}`;
  React.useEffect(() => {
    if (!pathRef.current) return;
    const len = pathRef.current.getTotalLength?.() || 0;
    pathRef.current.style.transition = "none";
    pathRef.current.style.strokeDasharray = `${len}`;
    pathRef.current.style.strokeDashoffset = `${len}`;
    pathRef.current.style.opacity = "0";
    pathRef.current.getBoundingClientRect();
    pathRef.current.style.transition = "stroke-dashoffset 1.6s cubic-bezier(.2,.7,.2,1), opacity .4s ease";
    pathRef.current.style.strokeDashoffset = "0";
    pathRef.current.style.opacity = "1";

    if (areaRef.current) {
      areaRef.current.style.transition = "none";
      areaRef.current.style.opacity = "0";
      areaRef.current.style.transform = "translateY(20px)";
      areaRef.current.getBoundingClientRect();
      areaRef.current.style.transition = "opacity 1.2s ease .5s, transform 1.2s cubic-bezier(.2,.7,.2,1) .5s";
      areaRef.current.style.opacity = "1";
      areaRef.current.style.transform = "translateY(0)";
    }
  }, [animKey]);

  // Smart tick generation for x-axis labels
  const ticks = React.useMemo(() => {
    if (!series || series.length === 0) return [];
    const n = series.length;
    const targetCount = 6;
    const stride = Math.max(1, Math.floor(n / (targetCount - 1)));
    const arr = [];
    for (let i = 0; i < n; i += stride) arr.push(i);
    if (arr[arr.length - 1] !== n - 1) arr.push(n - 1);
    return arr;
  }, [series]);

  const formatTick = (dateStr) => {
    const d = new Date(dateStr);
    if (timeframe === "1W") return d.toLocaleDateString(undefined, { weekday: "short", day: "numeric" });
    if (timeframe === "1M") return d.toLocaleDateString(undefined, { month: "short", day: "numeric" });
    if (timeframe === "3M") return d.toLocaleDateString(undefined, { month: "short", day: "numeric" });
    if (timeframe === "1Y") return d.toLocaleDateString(undefined, { month: "short", year: "2-digit" });
    if (timeframe === "5Y") return d.toLocaleDateString(undefined, { month: "short", year: "numeric" });
    return d.toLocaleDateString();
  };

  const formatHoverDate = (dateStr) => {
    const d = new Date(dateStr);
    return d.toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric", year: "numeric" });
  };

  const onMove = (e) => {
    if (!svgRef.current || !wrapRef.current || points.length === 0) return;
    const wrapRect = wrapRef.current.getBoundingClientRect();
    const svgRect = svgRef.current.getBoundingClientRect();
    const xSvg = ((e.clientX - svgRect.left) / svgRect.width) * W;
    let best = 0, bestD = Infinity;
    for (let i = 0; i < points.length; i++) {
      const d = Math.abs(points[i].x - xSvg);
      if (d < bestD) { bestD = d; best = i; }
    }
    if (best !== hoverIdx) {
      if (navigator.vibrate) navigator.vibrate(3);
    }
    setHoverIdx(best);
    // px coords in wrapper for floating tooltip
    const p = points[best];
    const px = (p.x / W) * svgRect.width + (svgRect.left - wrapRect.left);
    const py = (p.y / H) * svgRect.height + (svgRect.top - wrapRect.top);
    setHoverPx({ x: px, y: py });
  };

  const onLeave = () => {
    setHoverIdx(null);
    setHoverPx(null);
  };

  const first = points[0];
  const last = points[points.length - 1];
  const trendUp = last && first && last.value >= first.value;
  const hover = hoverIdx != null ? points[hoverIdx] : null;

  const fromCur = window.CURRENCY_BY_CODE[from];
  const toCur = window.CURRENCY_BY_CODE[to];

  const TIMEFRAMES = [
    { id: "1W", label: "1W", full: "7 days" },
    { id: "1M", label: "1M", full: "30 days" },
    { id: "3M", label: "3M", full: "90 days" },
    { id: "1Y", label: "1Y", full: "1 year" },
    { id: "5Y", label: "5Y", full: "5 years" },
  ];
  const tfFull = TIMEFRAMES.find(t => t.id === timeframe)?.full || "30 days";

  // Compute tooltip position with bounds clamping
  const tipW = 200, tipH = 76;
  let tipLeft = 0, tipTop = 0, tipFlipped = false;
  if (hoverPx && wrapRef.current) {
    const wrapW = wrapRef.current.clientWidth;
    tipLeft = Math.max(8, Math.min(wrapW - tipW - 8, hoverPx.x - tipW / 2));
    tipTop = hoverPx.y - tipH - 18;
    if (tipTop < 8) { tipTop = hoverPx.y + 18; tipFlipped = true; }
  }

  return (
    <div className="spark">
      <div className="spark__head">
        <div className="spark__head-left">
          <div className="spark__pair">
            {fromCur && (
              <div className="spark__flag-pair">
                <img src={`https://flagcdn.com/w80/${fromCur.country}.png`} alt={from}/>
                <img src={`https://flagcdn.com/w80/${toCur.country}.png`} alt={to}/>
              </div>
            )}
            <div>
              <div className="spark__pair-code">
                <span>{from}</span>
                <span className="spark__pair-sep">/</span>
                <span>{to}</span>
              </div>
              <div className="spark__sub">
                {`${fromCur?.symbol} → ${toCur?.symbol} · ${tfFull}`}
              </div>
            </div>
          </div>
        </div>

        <div className="spark__tf">
          <div className="spark__tf-track">
            {TIMEFRAMES.map(t => (
              <button
                key={t.id}
                className={`spark__tf-btn ${t.id === timeframe ? "active" : ""}`}
                onClick={() => onTimeframeChange && onTimeframeChange(t.id)}
              >
                {t.label}
              </button>
            ))}
            <div
              className="spark__tf-pill"
              style={{
                width: `${100 / TIMEFRAMES.length}%`,
                transform: `translateX(${TIMEFRAMES.findIndex(t => t.id === timeframe) * 100}%)`,
              }}
            ></div>
          </div>
        </div>

        <div className="spark__stats">
          <div className="spark__stat">
            <div className="spark__stat-label">LOW</div>
            <div className="spark__stat-val">{min ? min.toFixed(4) : "—"}</div>
          </div>
          <div className="spark__stat">
            <div className="spark__stat-label">HIGH</div>
            <div className="spark__stat-val">{max ? max.toFixed(4) : "—"}</div>
          </div>
          <div className={`spark__stat ${trendUp ? "up" : "down"}`}>
            <div className="spark__stat-label">CHG</div>
            <div className="spark__stat-val">
              {first && last
                ? `${trendUp ? "▲" : "▼"} ${(((last.value - first.value) / first.value) * 100).toFixed(2)}%`
                : "—"}
            </div>
          </div>
        </div>
      </div>

      <div className="spark__wrap" ref={wrapRef}>
        <svg
          ref={svgRef}
          className="spark__svg"
          viewBox={`0 0 ${W} ${H}`}
          preserveAspectRatio="none"
          onMouseMove={onMove}
          onMouseLeave={onLeave}
        >
          <defs>
            <linearGradient id="sparkArea" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor="rgba(80, 230, 210, 0.35)"/>
              <stop offset="100%" stopColor="rgba(80, 230, 210, 0)"/>
            </linearGradient>
            <linearGradient id="sparkLine" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stopColor="#7af0d8"/>
              <stop offset="100%" stopColor="#5ad6ff"/>
            </linearGradient>
            <filter id="sparkGlow">
              <feGaussianBlur stdDeviation="2.2" result="b"/>
              <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
            </filter>
          </defs>

          {/* Grid lines */}
          {[0.25, 0.5, 0.75].map((f, i) => (
            <line key={i} x1={P} x2={W - P} y1={P + f * (H - 2 * P)} y2={P + f * (H - 2 * P)}
                  stroke="rgba(255,255,255,0.04)" strokeDasharray="2 4"/>
          ))}

          {pathD && (
            <>
              <path ref={areaRef} d={areaD} fill="url(#sparkArea)" opacity={loading ? 0.3 : 1}/>
              <path
                ref={pathRef}
                d={pathD}
                fill="none"
                stroke="url(#sparkLine)"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
                filter="url(#sparkGlow)"
              />
              {hover && (
                <g>
                  <line x1={hover.x} x2={hover.x} y1={P} y2={H - P} stroke="rgba(122,240,216,0.4)" strokeDasharray="3 3"/>
                  <circle cx={hover.x} cy={hover.y} r="7" fill="#7af0d8" opacity="0.18" className="spark-halo"/>
                  <circle cx={hover.x} cy={hover.y} r="3.5" fill="#7af0d8"/>
                </g>
              )}
              {!hover && last && (
                <circle cx={last.x} cy={last.y} r="3.5" fill="#7af0d8" className="spark-pulse-dot"/>
              )}
            </>
          )}

          {loading && (
            <text x={W / 2} y={H / 2} textAnchor="middle" fill="rgba(255,255,255,0.3)"
                  style={{ font: "12px 'JetBrains Mono', monospace" }}>
              LOADING HISTORICAL DATA…
            </text>
          )}

          {!loading && !pathD && !histAvailable && (
            <text x={W / 2} y={H / 2} textAnchor="middle" fill="rgba(255,255,255,0.32)"
                  style={{ font: "11px 'JetBrains Mono', monospace", letterSpacing: "0.10em" }}>
              <tspan x={W / 2} dy="-6">HISTORICAL CHART UNAVAILABLE FOR THIS PAIR</tspan>
              <tspan x={W / 2} dy="18" fill="rgba(255,255,255,0.20)" style={{ fontSize: "10px" }}>
                ECB tracks ~30 major currencies · live rate above is current
              </tspan>
            </text>
          )}
        </svg>

        {/* Floating tooltip bubble */}
        {hover && hoverPx && (
          <div
            className={`spark__tip ${tipFlipped ? "flipped" : ""}`}
            style={{
              left: `${tipLeft}px`,
              top: `${tipTop}px`,
              width: `${tipW}px`,
            }}
          >
            <div className="spark__tip-glass"></div>
            <div className="spark__tip-edge"></div>
            <div className="spark__tip-content">
              <div className="spark__tip-date">{formatHoverDate(hover.date)}</div>
              <div className="spark__tip-row">
                <span className="spark__tip-pair">1 {from} =</span>
                <span className="spark__tip-val">
                  {hover.value.toFixed(6)} <em>{to}</em>
                </span>
              </div>
            </div>
            <div className="spark__tip-arrow" aria-hidden></div>
          </div>
        )}
      </div>

      {/* X-axis timescale */}
      <div className="spark__axis">
        {ticks.map((i, idx) => {
          const p = points[i];
          if (!p) return null;
          const leftPct = ((p.x - P) / (W - 2 * P)) * 100;
          const isActive = hover && hoverIdx === i;
          return (
            <div
              key={idx}
              className={`spark__axis-tick ${isActive ? "active" : ""}`}
              style={{ left: `${leftPct}%`, animationDelay: `${idx * 60}ms` }}
            >
              <div className="spark__axis-mark"></div>
              <div className="spark__axis-label">{formatTick(p.date)}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

window.Sparkline = Sparkline;
