/* charts.jsx — SVG editorial chart primitives for EcoID
   Loaded as <script type="text/babel">. Exports to window.
*/

const { useState, useEffect, useRef, useMemo } = React;

// ---------- Number formatting (id-ID) ----------
const fmtIDR = (n, d = 1) => {
  if (n === undefined || n === null) return "—";
  const abs = Math.abs(n);
  if (abs >= 1_000_000) return `Rp${(n/1_000_000).toFixed(d)}M`;
  if (abs >= 1_000) return `Rp${(n/1_000).toFixed(d)}rb`;
  return `Rp${n.toLocaleString('id-ID')}`;
};
const fmtT = (n, d = 1) => `Rp${n.toFixed(d).replace('.', ',')}T`;
const fmtPct = (n, d = 1) => `${n.toFixed(d).replace('.', ',')}%`;
const fmtNum = (n, d = 0) => n.toLocaleString('id-ID', { minimumFractionDigits: d, maximumFractionDigits: d });

// ---------- Tooltip ----------
function useTooltip() {
  const [tt, setTt] = useState(null);
  const show = (e, content, src) => {
    setTt({
      x: e.clientX,
      y: e.clientY,
      content, src
    });
  };
  const hide = () => setTt(null);
  const node = tt ? (
    <div className="tt" style={{ left: tt.x, top: tt.y }}>
      <div>{tt.content}</div>
      {tt.src ? <div className="src">{tt.src}</div> : null}
    </div>
  ) : null;
  return { show, hide, node };
}

// ---------- Flag Button (data accountability) ----------
function FlagButton({ id, onFlag }) {
  const [flagged, setFlagged] = useState(false);
  return (
    <button
      className={`flag-btn ${flagged ? 'flagged' : ''}`}
      title={flagged ? "Sudah ditandai untuk review" : "Tandai data ini"}
      onClick={(e) => {
        e.stopPropagation();
        setFlagged(!flagged);
        if (onFlag) onFlag(id, !flagged);
      }}
    >
      <svg width="11" height="13" viewBox="0 0 11 13" fill="none">
        <path d="M1 1V12M1 1H10L8 4L10 7H1" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round"/>
      </svg>
    </button>
  );
}

// ---------- KPI Card ----------
function KPI({ label, value, sub, delta, deltaType = "up", src, unit, flag, onAnnotate, mono }) {
  return (
    <div className="kpi">
      <div className="label">{label}</div>
      <div className="val">
        {value}
        {unit ? <span style={{ fontSize: '0.45em', color: 'var(--fg-3)', marginLeft: 6, fontWeight: 500 }}>{unit}</span> : null}
      </div>
      {sub ? <div className="sub">{sub}</div> : null}
      {delta ? <div className={`delta ${deltaType}`}>
        <span>{deltaType === 'up' ? '▲' : deltaType === 'down' ? '▼' : deltaType === 'pos' ? '↑' : '—'}</span>
        {delta}
      </div> : null}
      {src ? <div className="src">{src}</div> : null}
      {flag !== false ? <FlagButton id={label} onFlag={onAnnotate}/> : null}
    </div>
  );
}

// ---------- Sparkline ----------
function Sparkline({ data, color = "var(--eco-red)", height = 36, width = 140 }) {
  const min = Math.min(...data), max = Math.max(...data);
  const span = max - min || 1;
  const points = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / span) * height;
    return `${x},${y}`;
  }).join(' ');
  return (
    <svg width={width} height={height} style={{ display: 'block' }}>
      <polyline points={points} fill="none" stroke={color} strokeWidth="1.5"/>
      <circle cx={width} cy={height - ((data[data.length-1] - min) / span) * height} r="3" fill={color}/>
    </svg>
  );
}

// ---------- Bar Chart (horizontal, editorial) ----------
function BarChart({ data, max, height = 280, color = "var(--eco-red)", showValues = true, valueFormat = (v) => v, accent }) {
  const m = max ?? Math.max(...data.map(d => d.value)) * 1.1;
  const tooltip = useTooltip();
  const barH = 26;
  const gap = 10;
  return (
    <div style={{ position: 'relative' }}>
      {tooltip.node}
      <div style={{ display: 'flex', flexDirection: 'column', gap }}>
        {data.map((d, i) => {
          const w = (d.value / m) * 100;
          const isAccent = accent && accent.includes(d.label);
          return (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <div style={{
                width: 180, fontSize: 12, color: 'var(--fg-2)',
                textAlign: 'right', flexShrink: 0, fontWeight: isAccent ? 600 : 400
              }}>{d.label}</div>
              <div style={{ flex: 1, height: barH, position: 'relative', background: 'var(--bg-sunken)' }}>
                <div
                  className="svg-bar"
                  style={{
                    height: '100%', width: `${w}%`,
                    background: d.color || (isAccent ? 'var(--eco-red)' : color),
                    transition: 'width 600ms cubic-bezier(.22,.61,.36,1)'
                  }}
                  onMouseMove={(e) => tooltip.show(e, `${d.label}: ${valueFormat(d.value)}`, d.src)}
                  onMouseLeave={tooltip.hide}
                />
                {showValues && (
                  <div style={{
                    position: 'absolute',
                    left: w > 88 ? '50%' : `calc(${w}% + 8px)`,
                    color: w > 88 ? 'white' : 'var(--fg-1)',
                    top: 0, bottom: 0, display: 'flex', alignItems: 'center',
                    fontSize: 12, fontWeight: 600, fontVariantNumeric: 'tabular-nums',
                    pointerEvents: 'none'
                  }}>{valueFormat(d.value)}</div>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------- Stacked Bar ----------
function StackedBar({ segments, height = 24, total, showLabels = false }) {
  const t = total ?? segments.reduce((s, x) => s + x.value, 0);
  const tooltip = useTooltip();
  return (
    <>
      {tooltip.node}
      <div style={{ display: 'flex', height, width: '100%', border: '1px solid var(--border)' }}>
        {segments.map((s, i) => {
          const pct = (s.value / t) * 100;
          return (
            <div key={i}
              className="svg-bar"
              style={{
                width: `${pct}%`, background: s.color,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontSize: 11, fontWeight: 600, color: s.textColor || 'white',
                borderRight: i < segments.length - 1 ? '1px solid rgba(255,255,255,0.4)' : 'none',
              }}
              onMouseMove={(e) => tooltip.show(e, `${s.label}: ${s.valueLabel || s.value} (${pct.toFixed(1)}%)`, s.src)}
              onMouseLeave={tooltip.hide}
            >
              {showLabels && pct > 8 ? `${pct.toFixed(0)}%` : ''}
            </div>
          );
        })}
      </div>
    </>
  );
}

// ---------- Line Chart ----------
function LineChart({ series, height = 260, xLabels, yMax, yMin, yFmt = (v) => v, highlight, threshold, thresholdLabel }) {
  const W = 600;
  const H = height;
  const padL = 50, padR = 20, padT = 20, padB = 30;
  const innerW = W - padL - padR;
  const innerH = H - padT - padB;
  const allVals = series.flatMap(s => s.data);
  const max = yMax ?? Math.max(...allVals) * 1.1;
  const min = yMin ?? Math.min(...allVals) * 0.95;
  const span = max - min;
  const n = series[0].data.length;
  const x = (i) => padL + (i / (n - 1)) * innerW;
  const y = (v) => padT + (1 - (v - min) / span) * innerH;
  const tooltip = useTooltip();

  // gridlines
  const ticks = 4;
  const gridY = Array.from({ length: ticks + 1 }, (_, i) => min + (span * i / ticks));

  return (
    <div style={{ position: 'relative' }}>
      {tooltip.node}
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" preserveAspectRatio="xMidYMid meet" style={{ overflow: 'visible' }}>
        {/* gridlines */}
        {gridY.map((g, i) => (
          <g key={i}>
            <line x1={padL} x2={W - padR} y1={y(g)} y2={y(g)} stroke="var(--border-soft)" strokeDasharray={i === 0 ? '0' : '2 3'}/>
            <text x={padL - 8} y={y(g) + 4} fontSize="10" fill="var(--fg-3)" textAnchor="end" fontFamily="var(--font-mono)">{yFmt(g)}</text>
          </g>
        ))}
        {/* threshold */}
        {threshold !== undefined && (
          <g>
            <line x1={padL} x2={W - padR} y1={y(threshold)} y2={y(threshold)} stroke="var(--eco-red)" strokeWidth="1.5" strokeDasharray="4 3"/>
            <text x={W - padR} y={y(threshold) - 6} fontSize="10" fill="var(--eco-red)" textAnchor="end" fontWeight="600">{thresholdLabel || `${yFmt(threshold)}`}</text>
          </g>
        )}
        {/* x labels */}
        {xLabels && xLabels.map((lbl, i) => (
          <text key={i} x={x(i)} y={H - 8} fontSize="10" fill="var(--fg-3)" textAnchor="middle">{lbl}</text>
        ))}
        {/* lines */}
        {series.map((s, si) => {
          const path = s.data.map((v, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(v)}`).join(' ');
          // Area fill optional
          const areaPath = s.area ? `${path} L ${x(n-1)} ${y(min)} L ${x(0)} ${y(min)} Z` : null;
          return (
            <g key={si}>
              {areaPath && <path d={areaPath} fill={s.color} opacity="0.08"/>}
              <path d={path} fill="none" stroke={s.color} strokeWidth={s.width || 2} strokeDasharray={s.dash || '0'} strokeLinecap="round" strokeLinejoin="round"/>
              {s.data.map((v, i) => (
                <circle
                  key={i} cx={x(i)} cy={y(v)} r={highlight === i ? 5 : 3}
                  fill={s.color}
                  onMouseMove={(e) => tooltip.show(e, `${s.name} ${xLabels ? xLabels[i] : ''}: ${yFmt(v)}`, s.src)}
                  onMouseLeave={tooltip.hide}
                  style={{ cursor: 'pointer' }}
                />
              ))}
            </g>
          );
        })}
      </svg>
      {/* legend */}
      {series.length > 1 && (
        <div style={{ display: 'flex', gap: 16, marginTop: 8, flexWrap: 'wrap' }}>
          {series.map((s, i) => (
            <div key={i} style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: 12, color: 'var(--fg-2)' }}>
              <span style={{ width: 16, height: 2, background: s.color, display: 'inline-block', borderTop: s.dash ? `2px dashed ${s.color}` : 'none' }}/>
              {s.name}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------- Waterfall Chart ----------
function Waterfall({ steps, height = 280, valueFmt = (v) => v }) {
  // steps: [{ label, value (signed), type: 'start'|'add'|'sub'|'end', color? }]
  // Compute cumulative
  const W = 720;
  const H = height;
  const padL = 60, padR = 30, padT = 30, padB = 80;
  const innerW = W - padL - padR;
  const innerH = H - padT - padB;
  let running = 0;
  const tooltip = useTooltip();

  const bars = steps.map((s, i) => {
    let start, end;
    if (s.type === 'start') { start = 0; end = s.value; running = s.value; }
    else if (s.type === 'end') { start = 0; end = s.value; running = s.value; }
    else {
      start = running;
      end = running + s.value;
      running = end;
    }
    return { ...s, start, end, top: Math.max(start, end), bottom: Math.min(start, end) };
  });

  const allVals = bars.flatMap(b => [b.start, b.end]);
  const max = Math.max(...allVals) * 1.08;
  const min = 0;

  const bw = innerW / (steps.length * 1.5);
  const x = (i) => padL + i * (bw * 1.5) + bw * 0.25;
  const y = (v) => padT + (1 - (v - min) / (max - min)) * innerH;

  const colorMap = {
    start: 'var(--eco-ink)',
    end: 'var(--eco-teal)',
    sub: 'var(--eco-teal)',
    add: 'var(--eco-red)',
    invest: 'var(--eco-amber)',
  };

  return (
    <div style={{ position: 'relative' }}>
      {tooltip.node}
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" preserveAspectRatio="xMidYMid meet" style={{ overflow: 'visible' }}>
        {/* baseline */}
        <line x1={padL} x2={W - padR} y1={y(0)} y2={y(0)} stroke="var(--eco-ink)" strokeWidth="1"/>
        {bars.map((b, i) => {
          const yTop = y(b.top);
          const h = Math.abs(y(b.bottom) - y(b.top));
          const col = b.color || colorMap[b.type] || 'var(--fg-3)';
          return (
            <g key={i}>
              <rect
                className="svg-bar"
                x={x(i)} y={yTop} width={bw} height={h}
                fill={col}
                onMouseMove={(e) => tooltip.show(e, `${b.label}: ${valueFmt(b.value)}`, b.src)}
                onMouseLeave={tooltip.hide}
              />
              {/* connector line to next */}
              {i < bars.length - 1 && b.type !== 'end' && (
                <line x1={x(i) + bw} x2={x(i+1)} y1={y(b.end)} y2={y(b.end)}
                  stroke="var(--fg-3)" strokeDasharray="3 2" strokeWidth="1"/>
              )}
              {/* label above bar */}
              <text x={x(i) + bw/2} y={yTop - 8} fontSize="11" textAnchor="middle" fontWeight="600" fill="var(--fg-1)" style={{ fontVariantNumeric: 'tabular-nums' }}>
                {b.type === 'sub' ? '−' : b.type === 'add' ? '+' : ''}{valueFmt(Math.abs(b.value))}
              </text>
              {/* label below */}
              <foreignObject x={x(i) - bw*0.2} y={H - padB + 10} width={bw * 1.4} height={padB - 20}>
                <div style={{
                  fontSize: 11, color: 'var(--fg-2)', textAlign: 'center', lineHeight: 1.25,
                  fontWeight: b.type === 'start' || b.type === 'end' ? 600 : 400
                }}>{b.label}</div>
              </foreignObject>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

// ---------- Risk Chain (chain diagram) ----------
function RiskChain({ nodes }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: `repeat(${nodes.length}, 1fr)`, gap: 0, alignItems: 'stretch' }}>
      {nodes.map((n, i) => (
        <div key={i} style={{ position: 'relative' }}>
          <div style={{
            background: n.color || 'var(--bg-elev)',
            color: n.color ? 'white' : 'var(--fg-1)',
            padding: '14px 16px', border: '1px solid var(--border)',
            borderLeft: i === 0 ? `4px solid var(--eco-red)` : '1px solid var(--border)',
            height: '100%',
          }}>
            <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', opacity: 0.7, fontWeight: 700 }}>
              Stage {i + 1}
            </div>
            <div style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 700, marginTop: 4, lineHeight: 1.2 }}>
              {n.title}
            </div>
            <div style={{ fontSize: 11, marginTop: 6, opacity: 0.85, lineHeight: 1.45 }}>{n.detail}</div>
            {n.metric && <div style={{ marginTop: 8, fontSize: 14, fontWeight: 700, fontFamily: 'var(--font-display)' }}>{n.metric}</div>}
          </div>
          {i < nodes.length - 1 && (
            <div style={{
              position: 'absolute', right: -10, top: '50%', transform: 'translateY(-50%)',
              zIndex: 2, background: 'var(--bg)', padding: '2px 4px',
              color: 'var(--eco-red)', fontWeight: 700
            }}>→</div>
          )}
        </div>
      ))}
    </div>
  );
}

// ---------- Progress / Deficit gauge ----------
function ProgressBar({ value, max, label, used, color = "var(--eco-red)" }) {
  const pct = (value / max) * 100;
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
        <div style={{ fontSize: 12, color: 'var(--fg-2)', fontWeight: 500 }}>{label}</div>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 20, fontWeight: 700 }}>
          {used || `${pct.toFixed(1).replace('.', ',')}%`}
        </div>
      </div>
      <div style={{ position: 'relative', height: 14, background: 'var(--bg-sunken)', border: '1px solid var(--border)' }}>
        <div style={{ width: `${Math.min(pct, 100)}%`, height: '100%', background: color, transition: 'width 800ms cubic-bezier(.22,.61,.36,1)' }}/>
        {pct > 100 && <div style={{ position: 'absolute', right: 0, top: 0, bottom: 0, width: 4, background: 'var(--eco-ink)' }}/>}
      </div>
    </div>
  );
}

// ---------- Annotation Sidebar ----------
function AnnotationSidebar({ open, onClose, annotations, mode }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  return (
    <>
      <div
        className={`annot-backdrop ${open ? 'open' : ''}`}
        onClick={onClose}
        aria-hidden="true"
      />
      <aside
        className={`annot-sidebar ${open ? 'open' : ''}`}
        role="dialog"
        aria-modal="true"
        aria-label="Catatan Pakar"
      >
      <header>
        <div>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18 }}>Catatan Pakar</div>
          <div style={{ fontSize: 11, color: 'var(--fg-3)', letterSpacing: '0.02em' }}>{annotations.length} respons · verified contributors</div>
        </div>
        <button className="close" onClick={onClose} aria-label="Tutup" autoFocus>✕</button>
      </header>
      <div className="body">
        <div style={{ background: 'var(--eco-paper-2)', padding: 14, marginBottom: 16, borderLeft: '3px solid var(--eco-red)' }}>
          <div style={{ fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 700, color: 'var(--eco-red)' }}>Open Review</div>
          <div style={{ fontSize: 13, marginTop: 4, color: 'var(--fg-2)' }}>
            Platform ini mengundang koreksi publik. Klik <strong>bendera</strong> di sebelah data manapun untuk meminta verifikasi.
          </div>
        </div>
        {annotations.map((a, i) => (
          <div className="annot" key={i}>
            <div className="who">
              <div className="avatar">{a.initials}</div>
              <div>
                <div className="name">{a.name}{a.verified && <span className="verified">✓ verified</span>}</div>
                <div className="role">{a.role}</div>
              </div>
            </div>
            <div className="quote">{a.text}</div>
            <div className="ref">{a.ref}</div>
          </div>
        ))}
      </div>
      </aside>
    </>
  );
}

// ---------- Quote / Pullquote ----------
function Pullquote({ children, attr }) {
  return (
    <blockquote style={{
      margin: 0, padding: '24px 0',
      borderTop: '2px solid var(--eco-ink)',
      borderBottom: '1px solid var(--border)',
    }}>
      <p style={{
        fontFamily: 'var(--font-display)', fontStyle: 'italic',
        fontSize: 26, lineHeight: 1.3, fontWeight: 500,
        letterSpacing: '-0.01em', color: 'var(--fg-1)'
      }}>
        "{children}"
      </p>
      <div style={{ marginTop: 12, fontSize: 12, color: 'var(--fg-3)', letterSpacing: '0.08em', textTransform: 'uppercase', fontWeight: 600 }}>
        — {attr}
      </div>
    </blockquote>
  );
}

// ---------- Source line ----------
function Source({ children }) {
  return (
    <div style={{
      fontSize: 11, color: 'var(--fg-3)',
      fontFamily: 'var(--font-mono)', letterSpacing: '0.02em',
      marginTop: 8
    }}>
      Sumber: {children}
    </div>
  );
}

// Export
Object.assign(window, {
  fmtIDR, fmtT, fmtPct, fmtNum,
  useTooltip, FlagButton, KPI, Sparkline,
  BarChart, StackedBar, LineChart, Waterfall,
  RiskChain, ProgressBar, AnnotationSidebar, Pullquote, Source,
});
