// SVG charts — sparkline, area, donut, bars. No external libs.
(function () {
  const { useMemo, useState, useRef, useEffect } = React;

  // ---------- helpers ----------
  function makePath(points, w, h, padding = 4) {
    if (!points.length) return '';
    const max = Math.max(...points, 1);
    const min = Math.min(...points, 0);
    const range = Math.max(max - min, 1);
    const stepX = (w - padding * 2) / Math.max(points.length - 1, 1);
    return points.map((p, i) => {
      const x = padding + i * stepX;
      const y = padding + (h - padding * 2) * (1 - (p - min) / range);
      return (i === 0 ? 'M' : 'L') + x.toFixed(2) + ',' + y.toFixed(2);
    }).join(' ');
  }
  function makeAreaPath(points, w, h, padding = 4) {
    if (!points.length) return '';
    const max = Math.max(...points, 1);
    const min = Math.min(...points, 0);
    const range = Math.max(max - min, 1);
    const stepX = (w - padding * 2) / Math.max(points.length - 1, 1);
    let d = '';
    points.forEach((p, i) => {
      const x = padding + i * stepX;
      const y = padding + (h - padding * 2) * (1 - (p - min) / range);
      d += (i === 0 ? 'M' : 'L') + x.toFixed(2) + ',' + y.toFixed(2);
    });
    d += ` L ${padding + (points.length - 1) * stepX},${h - padding} L ${padding},${h - padding} Z`;
    return d;
  }

  // ---------- Sparkline ----------
  function Sparkline({ points, color = '#ffb547', height = 36, width = 120, fill = true }) {
    const id = useMemo(() => 'spk-' + Math.random().toString(36).slice(2, 9), []);
    return (
      <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" style={{ display: 'block' }}>
        <defs>
          <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.35" />
            <stop offset="100%" stopColor={color} stopOpacity="0" />
          </linearGradient>
        </defs>
        {fill && <path d={makeAreaPath(points, width, height, 2)} fill={`url(#${id})`} />}
        <path d={makePath(points, width, height, 2)} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    );
  }

  // ---------- Big area chart ----------
  function AreaChart({ series, height = 280, labels, yFormat = v => v }) {
    // series: [{ name, color, points: [v0..vN] }]
    const wrapRef = useRef(null);
    const [w, setW] = useState(800);
    useEffect(() => {
      if (!wrapRef.current) return;
      const ro = new ResizeObserver(entries => {
        for (const e of entries) setW(Math.max(320, e.contentRect.width));
      });
      ro.observe(wrapRef.current);
      return () => ro.disconnect();
    }, []);

    const [hover, setHover] = useState(null); // {i, x}

    const pad = { l: 56, r: 16, t: 16, b: 28 };
    const innerW = w - pad.l - pad.r;
    const innerH = height - pad.t - pad.b;
    const n = series[0]?.points.length || 0;
    const maxAll = Math.max(1, ...series.flatMap(s => s.points));
    // Round up to nice number
    const niceMax = niceCeil(maxAll);
    const stepX = innerW / Math.max(n - 1, 1);

    const ticks = 4;
    const yTicks = Array.from({ length: ticks + 1 }, (_, i) => (niceMax * i) / ticks);

    function xy(s, i) {
      const x = pad.l + i * stepX;
      const y = pad.t + innerH * (1 - s.points[i] / niceMax);
      return [x, y];
    }

    function handleMove(e) {
      const rect = e.currentTarget.getBoundingClientRect();
      const mx = e.clientX - rect.left - pad.l;
      const i = Math.round(mx / stepX);
      if (i >= 0 && i < n) setHover({ i, x: pad.l + i * stepX });
    }

    return (
      <div ref={wrapRef} style={{ width: '100%', position: 'relative' }}>
        <svg width={w} height={height} onMouseMove={handleMove} onMouseLeave={() => setHover(null)} style={{ cursor: 'crosshair' }}>
          {/* Y grid */}
          {yTicks.map((t, i) => {
            const y = pad.t + innerH * (1 - t / niceMax);
            return (
              <g key={i}>
                <line x1={pad.l} x2={w - pad.r} y1={y} y2={y} stroke="rgba(255,255,255,0.04)" strokeDasharray="2 4" />
                <text x={pad.l - 8} y={y + 3} textAnchor="end" fill="rgba(230,233,240,0.4)" fontSize="10" fontFamily="'IBM Plex Mono', monospace">{yFormat(t)}</text>
              </g>
            );
          })}
          {/* Defs */}
          <defs>
            {series.map((s, si) => (
              <linearGradient key={si} id={`area-${si}`} x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor={s.color} stopOpacity="0.28" />
                <stop offset="100%" stopColor={s.color} stopOpacity="0" />
              </linearGradient>
            ))}
          </defs>
          {/* Area fills */}
          {series.map((s, si) => {
            const pts = s.points.map((_, i) => xy(s, i));
            const d = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0] + ',' + p[1]).join(' ')
              + ` L ${pad.l + (n - 1) * stepX},${pad.t + innerH} L ${pad.l},${pad.t + innerH} Z`;
            return <path key={si} d={d} fill={`url(#area-${si})`} />;
          })}
          {/* Stroke lines */}
          {series.map((s, si) => {
            const pts = s.points.map((_, i) => xy(s, i));
            const d = pts.map((p, i) => (i === 0 ? 'M' : 'L') + p[0] + ',' + p[1]).join(' ');
            return <path key={si} d={d} fill="none" stroke={s.color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />;
          })}
          {/* X axis labels */}
          {labels && labels.map((lab, i) => {
            const x = pad.l + i * stepX;
            return <text key={i} x={x} y={height - 8} textAnchor="middle" fill="rgba(230,233,240,0.4)" fontSize="10" fontFamily="'IBM Plex Mono', monospace">{lab}</text>;
          })}
          {/* Hover crosshair */}
          {hover && (
            <g>
              <line x1={hover.x} x2={hover.x} y1={pad.t} y2={pad.t + innerH} stroke="rgba(255,181,71,0.5)" strokeDasharray="2 2" />
              {series.map((s, si) => {
                const [x, y] = xy(s, hover.i);
                return (
                  <g key={si}>
                    <circle cx={x} cy={y} r="6" fill={s.color} opacity="0.2" />
                    <circle cx={x} cy={y} r="3" fill={s.color} stroke="#0a0d14" strokeWidth="2" />
                  </g>
                );
              })}
            </g>
          )}
        </svg>
        {hover && (
          <div style={{
            position: 'absolute', top: 12, right: 12, padding: '10px 12px',
            background: 'rgba(15,19,32,0.88)', border: '1px solid rgba(255,181,71,0.18)',
            borderRadius: 8, fontSize: 11, color: '#e6e9f0',
            backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)',
            fontFamily: "'IBM Plex Mono', monospace", pointerEvents: 'none',
            boxShadow: '0 10px 30px rgba(0,0,0,0.4)',
          }}>
            <div style={{ opacity: 0.5, marginBottom: 6 }}>{labels && labels[hover.i]}</div>
            {series.map((s, si) => (
              <div key={si} style={{ display: 'flex', alignItems: 'center', gap: 8, lineHeight: '18px' }}>
                <span style={{ width: 8, height: 8, borderRadius: 2, background: s.color }}></span>
                <span style={{ opacity: 0.7 }}>{s.name}</span>
                <span style={{ marginLeft: 'auto', fontWeight: 600 }}>{yFormat(s.points[hover.i])}</span>
              </div>
            ))}
          </div>
        )}
      </div>
    );
  }

  function niceCeil(v) {
    if (v <= 0) return 1;
    const exp = Math.floor(Math.log10(v));
    const base = Math.pow(10, exp);
    const n = v / base;
    let nice;
    if (n <= 1) nice = 1; else if (n <= 2) nice = 2; else if (n <= 5) nice = 5; else nice = 10;
    return nice * base;
  }

  // ---------- Bar chart (vertical bars for stock movement) ----------
  function BarChart({ data, height = 220, palette }) {
    // data: [{ label, valueIn, valueOut }]
    const wrapRef = useRef(null);
    const [w, setW] = useState(800);
    useEffect(() => {
      if (!wrapRef.current) return;
      const ro = new ResizeObserver(entries => {
        for (const e of entries) setW(Math.max(320, e.contentRect.width));
      });
      ro.observe(wrapRef.current);
      return () => ro.disconnect();
    }, []);
    const pad = { l: 32, r: 12, t: 12, b: 28 };
    const innerW = w - pad.l - pad.r;
    const innerH = height - pad.t - pad.b;
    const max = Math.max(1, ...data.flatMap(d => [d.valueIn, d.valueOut]));
    const niceMax = niceCeil(max);
    const groupW = innerW / data.length;
    const barW = Math.max(2, Math.min(14, groupW * 0.32));
    const [hover, setHover] = useState(null);

    return (
      <div ref={wrapRef} style={{ width: '100%', position: 'relative' }}>
        <svg width={w} height={height}>
          {[0, 0.5, 1].map((t, i) => {
            const y = pad.t + innerH * (1 - t);
            return <line key={i} x1={pad.l} x2={w - pad.r} y1={y} y2={y} stroke="rgba(255,255,255,0.04)" strokeDasharray="2 4" />;
          })}
          {data.map((d, i) => {
            const cx = pad.l + groupW * (i + 0.5);
            const hIn = (d.valueIn / niceMax) * innerH;
            const hOut = (d.valueOut / niceMax) * innerH;
            return (
              <g key={i} onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)} style={{ cursor: 'pointer' }}>
                <rect x={cx - barW - 1} y={pad.t + innerH - hIn} width={barW} height={hIn} fill={palette.in} rx="2" opacity={hover === null || hover === i ? 1 : 0.4} />
                <rect x={cx + 1} y={pad.t + innerH - hOut} width={barW} height={hOut} fill={palette.out} rx="2" opacity={hover === null || hover === i ? 1 : 0.4} />
              </g>
            );
          })}
          {data.filter((_, i) => i % Math.max(1, Math.floor(data.length / 6)) === 0).map((d, idx) => {
            const i = data.indexOf(d);
            const cx = pad.l + groupW * (i + 0.5);
            return <text key={idx} x={cx} y={height - 8} textAnchor="middle" fill="rgba(230,233,240,0.4)" fontSize="10" fontFamily="'IBM Plex Mono', monospace">{d.label}</text>;
          })}
        </svg>
        {hover !== null && (
          <div style={{
            position: 'absolute', top: 0, left: Math.min(w - 160, pad.l + (innerW / data.length) * (hover + 0.5)),
            transform: 'translateX(-50%)',
            padding: '8px 10px', background: 'rgba(15,19,32,0.88)',
            border: '1px solid rgba(255,181,71,0.18)', borderRadius: 6,
            fontSize: 11, color: '#e6e9f0',
            fontFamily: "'IBM Plex Mono', monospace", pointerEvents: 'none',
            backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
            whiteSpace: 'nowrap',
          }}>
            <div style={{ opacity: 0.5, marginBottom: 4 }}>{data[hover].label}</div>
            <div style={{ color: palette.in }}>รับเข้า: {data[hover].valueIn}</div>
            <div style={{ color: palette.out }}>จ่ายออก: {data[hover].valueOut}</div>
          </div>
        )}
      </div>
    );
  }

  // ---------- Donut ----------
  function Donut({ segments, size = 160, thickness = 18, centerLabel, centerValue }) {
    const r = size / 2 - thickness / 2 - 2;
    const c = 2 * Math.PI * r;
    const total = segments.reduce((s, v) => s + v.value, 0) || 1;
    let acc = 0;
    return (
      <div style={{ position: 'relative', width: size, height: size }}>
        <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
          <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth={thickness} />
          {segments.map((seg, i) => {
            const len = (seg.value / total) * c;
            const dash = `${len} ${c - len}`;
            const offset = -acc;
            acc += len;
            return (
              <circle key={i} cx={size / 2} cy={size / 2} r={r} fill="none" stroke={seg.color}
                strokeWidth={thickness} strokeDasharray={dash} strokeDashoffset={offset}
                strokeLinecap="butt" style={{ transition: 'stroke-dasharray 600ms cubic-bezier(.2,.7,.3,1)' }} />
            );
          })}
        </svg>
        <div style={{
          position: 'absolute', inset: 0, display: 'flex',
          flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
        }}>
          <div style={{ fontSize: 10, letterSpacing: 1, color: 'rgba(230,233,240,0.5)', textTransform: 'uppercase' }}>{centerLabel}</div>
          <div style={{ fontSize: 20, fontWeight: 600, fontFamily: "'IBM Plex Mono', monospace" }}>{centerValue}</div>
        </div>
      </div>
    );
  }

  // ---------- Animated counter ----------
  function Counter({ value, format = v => v, duration = 900 }) {
    const [v, setV] = useState(0);
    const startRef = useRef(null);
    const fromRef = useRef(0);
    useEffect(() => {
      fromRef.current = v;
      startRef.current = null;
      let raf;
      function tick(t) {
        if (!startRef.current) startRef.current = t;
        const p = Math.min(1, (t - startRef.current) / duration);
        const eased = 1 - Math.pow(1 - p, 3);
        setV(fromRef.current + (value - fromRef.current) * eased);
        if (p < 1) raf = requestAnimationFrame(tick);
      }
      raf = requestAnimationFrame(tick);
      return () => cancelAnimationFrame(raf);
      // eslint-disable-next-line
    }, [value]);
    return <span>{format(v)}</span>;
  }

  Object.assign(window, { Sparkline, AreaChart, BarChart, Donut, Counter });
})();
