/* ============================================================
   Charts — hand-built SVG, graphite styled.
   StackedBar · AreaLine (dual axis) · SeenOutcomeFlow (sankey)
   All call onSlice handlers to open the Deal drawer.
   ============================================================ */

const CH = {
  core: '#3e6e8c', buyout: '#86a0ad', vc: '#c4b58c', other: '#cfd2d4',
  platform: '#3e6e8c', exit: '#b07a2e', buyAndBuild: '#3f7d58',
  area: '#c5d3db', areaLine: '#3e6e8c', pctLine: '#a4453c',
  axis: '#9aa0a5', grid: '#e7e8e9', ink: '#1a1c1e', muted: '#6e7479',
};

function niceMax(v) {
  if (v <= 5) return 5;
  const pow = Math.pow(10, Math.floor(Math.log10(v)));
  const n = v / pow;
  const step = n <= 1 ? 1 : n <= 2 ? 2 : n <= 5 ? 5 : 10;
  return Math.ceil(v / (step * pow / 5)) * (step * pow / 5);
}

function ChartTip({ tip }) {
  if (!tip) return null;
  return (
    <div style={{
      position: 'absolute', left: tip.x, top: tip.y, transform: 'translate(-50%,-114%)',
      background: '#1a1c1e', color: '#fff', padding: '6px 9px', borderRadius: 6,
      fontSize: 11.5, fontWeight: 500, whiteSpace: 'nowrap', pointerEvents: 'none',
      boxShadow: '0 6px 18px rgba(0,0,0,.22)', zIndex: 30, lineHeight: 1.35,
    }}>
      {tip.lines.map((l, i) => (
        <div key={i} style={{ opacity: i === 0 ? 1 : 0.82, fontWeight: i === 0 ? 700 : 500 }}>{l}</div>
      ))}
    </div>
  );
}

/* ---------- Stacked bar ---------- */
function StackedBar({ data, keys, colors, labels, onSegment, height = 220, unit = '' }) {
  const [tip, setTip] = React.useState(null);
  const wrapRef = React.useRef(null);
  const [W, setW] = React.useState(560);
  React.useEffect(() => {
    const el = wrapRef.current; if (!el) return;
    const measure = () => { const w = el.clientWidth; if (w) setW(Math.max(300, w)); };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);
  const pad = { l: 34, r: 12, t: 12, b: 30 };
  const H = height;
  const iw = W - pad.l - pad.r, ih = H - pad.t - pad.b;
  const totals = data.map((d) => keys.reduce((s, k) => s + (d[k] || 0), 0));
  const max = niceMax(Math.max(1, ...totals));
  // keep the bar cluster well-proportioned: fill the card with gentle side margins
  const maxStep = 200;
  const usable = Math.min(iw, data.length * maxStep);
  const ox = pad.l + (iw - usable) / 2;
  const step = usable / Math.max(1, data.length);
  const bw = Math.min(56, step * 0.5);
  const yOf = (v) => pad.t + ih - (v / max) * ih;
  const ticks = 4;

  return (
    <div ref={wrapRef} style={{ position: 'relative' }}>
      <svg viewBox={`0 0 ${W} ${H}`} width={W} height={H} style={{ display: 'block', overflow: 'visible', maxWidth: '100%' }}>
        {Array.from({ length: ticks + 1 }).map((_, i) => {
          const v = (max / ticks) * i, y = yOf(v);
          return (
            <g key={i}>
              <line x1={ox} x2={ox + usable} y1={y} y2={y} stroke={CH.grid} strokeWidth="1" />
              <text x={ox - 8} y={y + 3} textAnchor="end" fontSize="10" fill={CH.axis} fontFamily="var(--mono)">{Math.round(v)}</text>
            </g>
          );
        })}
        {data.map((d, di) => {
          const cx = ox + step * di + step / 2;
          let acc = 0;
          return (
            <g key={di} opacity={d.partial ? 0.5 : 1}>
              {keys.map((k) => {
                const val = d[k] || 0; if (!val) return null;
                const y0 = yOf(acc), y1 = yOf(acc + val); acc += val;
                return (
                  <rect key={k} x={cx - bw / 2} y={y1} width={bw} height={Math.max(0, y0 - y1)}
                    fill={colors[k]} rx="2"
                    style={{ cursor: onSegment ? 'pointer' : 'default', transition: 'opacity .12s' }}
                    onMouseEnter={(e) => setTip({ x: cx, y: (y0 + y1) / 2, lines: [`${labels[k]}: ${val}${unit}`, d.label + (d.partial ? ' · in progress' : '')] })}
                    onMouseMove={(e) => setTip((t) => t && { ...t })}
                    onMouseLeave={() => setTip(null)}
                    onClick={() => onSegment && onSegment(d, k)}
                  />
                );
              })}
              <text x={cx} y={H - pad.b + 17} textAnchor="middle" fontSize="10.5" fill={CH.muted} fontWeight="600">{d.label}</text>
              {d.partial && <text x={cx} y={H - pad.b + 27} textAnchor="middle" fontSize="8.5" fill={CH.axis} fontStyle="italic">in progress</text>}
            </g>
          );
        })}
      </svg>
      <ChartTip tip={tip} />
    </div>
  );
}

/* ---------- Area + line, dual axis ---------- */
function AreaLine({ data, onPoint, height = 230 }) {
  const [tip, setTip] = React.useState(null);
  const pad = { l: 34, r: 38, t: 14, b: 28 };
  const W = 560, H = height;
  const iw = W - pad.l - pad.r, ih = H - pad.t - pad.b;
  const maxTot = niceMax(Math.max(1, ...data.map((d) => d.total)));
  const xOf = (i) => pad.l + (data.length === 1 ? iw / 2 : (iw * i) / (data.length - 1));
  const yTot = (v) => pad.t + ih - (v / maxTot) * ih;
  const yPct = (v) => pad.t + ih - (v / 100) * ih;
  const areaPath = data.map((d, i) => `${i ? 'L' : 'M'}${xOf(i)},${yTot(d.total)}`).join(' ')
    + ` L${xOf(data.length - 1)},${pad.t + ih} L${xOf(0)},${pad.t + ih} Z`;
  const linePath = data.map((d, i) => `${i ? 'L' : 'M'}${xOf(i)},${yTot(d.total)}`).join(' ');
  const pctPath = data.map((d, i) => `${i ? 'L' : 'M'}${xOf(i)},${yPct(d.pct)}`).join(' ');
  const ticks = 4;

  return (
    <div style={{ position: 'relative' }}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block', overflow: 'visible' }}>
        {Array.from({ length: ticks + 1 }).map((_, i) => {
          const v = (maxTot / ticks) * i, y = yTot(v);
          return (
            <g key={i}>
              <line x1={pad.l} x2={W - pad.r} y1={y} y2={y} stroke={CH.grid} strokeWidth="1" />
              <text x={pad.l - 6} y={y + 3} textAnchor="end" fontSize="10" fill={CH.axis} fontFamily="var(--mono)">{Math.round(v)}</text>
              <text x={W - pad.r + 6} y={y + 3} textAnchor="start" fontSize="10" fill={CH.pctLine} fontFamily="var(--mono)">{Math.round((100 / ticks) * i)}%</text>
            </g>
          );
        })}
        <path d={areaPath} fill={CH.area} opacity="0.55" />
        <path d={linePath} fill="none" stroke={CH.areaLine} strokeWidth="2" />
        <path d={pctPath} fill="none" stroke={CH.pctLine} strokeWidth="2" strokeDasharray="4 3" />
        {data.map((d, i) => (
          <g key={i}>
            <circle cx={xOf(i)} cy={yPct(d.pct)} r="3" fill={CH.pctLine} />
            <circle cx={xOf(i)} cy={yTot(d.total)} r="3.5" fill="#fff" stroke={CH.areaLine} strokeWidth="2"
              style={{ cursor: onPoint ? 'pointer' : 'default' }}
              onMouseEnter={() => setTip({ x: xOf(i), y: yTot(d.total), lines: [`${d.total} deals · ${d.pct}% relevant`, d.label] })}
              onMouseLeave={() => setTip(null)}
              onClick={() => onPoint && onPoint(d)} />
            <text x={xOf(i)} y={H - pad.b + 16} textAnchor="middle" fontSize="10.5" fill={CH.muted} fontWeight="600">{d.label}</text>
          </g>
        ))}
      </svg>
      <ChartTip tip={tip} />
    </div>
  );
}

/* ---------- Seen vs Outcome flow (sankey) ---------- */
function SeenOutcomeFlow({ links, onLink, height = 250 }) {
  // links: [{from:'seen'|'unseen', to:'core'|'buyout'|'vc'|'other', value}]
  const [hov, setHov] = React.useState(null);
  const W = 560, H = height;
  const colX = { left: 150, right: 410 };
  const nodeW = 13, gap = 14;
  const leftKeys = ['seen', 'unseen'];
  const rightKeys = ['core', 'buyout', 'vc', 'other'];
  const leftLabel = { seen: 'Seen before', unseen: 'Unseen' };
  const rightLabel = { core: 'Won by Core', buyout: 'Won by Buyout', vc: 'Won by VC', other: 'Other / us' };
  const leftColor = { seen: '#3f7d58', unseen: '#a4453c' };
  const sum = (f) => (a) => links.filter(f).reduce((s, l) => s + l.value, (a || 0) * 0);
  const total = links.reduce((s, l) => s + l.value, 0) || 1;
  const top = 22, usable = H - top - 30;

  // node sizes
  const leftTot = {}, rightTot = {};
  leftKeys.forEach((k) => leftTot[k] = links.filter((l) => l.from === k).reduce((s, l) => s + l.value, 0));
  rightKeys.forEach((k) => rightTot[k] = links.filter((l) => l.to === k).reduce((s, l) => s + l.value, 0));
  const leftH = {}, rightH = {};
  const scale = (usable - gap * 1) / total;
  const rscale = (usable - gap * 3) / total;
  let ly = top; const leftY = {};
  leftKeys.forEach((k) => { leftH[k] = leftTot[k] * scale; leftY[k] = ly; ly += leftH[k] + gap; });
  let ry = top; const rightY = {};
  rightKeys.forEach((k) => { rightH[k] = rightTot[k] * rscale; rightY[k] = ry; ry += rightH[k] + gap; });

  // link ribbons, stacked at each node
  const loff = {}, roff = {};
  leftKeys.forEach((k) => loff[k] = 0); rightKeys.forEach((k) => roff[k] = 0);
  const ribbons = links.filter((l) => l.value > 0).map((l, i) => {
    const th = l.value * Math.min(scale, rscale);
    const y0 = leftY[l.from] + loff[l.from] + (l.value * scale) / 2; loff[l.from] += l.value * scale;
    const y1 = rightY[l.to] + roff[l.to] + (l.value * rscale) / 2; roff[l.to] += l.value * rscale;
    const x0 = colX.left + nodeW, x1 = colX.right;
    const mx = (x0 + x1) / 2;
    const d = `M${x0},${y0} C${mx},${y0} ${mx},${y1} ${x1},${y1}`;
    const key = l.from + '>' + l.to;
    return { d, th: Math.max(1.5, l.value * scale), key, l, color: leftColor[l.from], hl: hov === key };
  });

  return (
    <div style={{ position: 'relative' }}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block', overflow: 'visible' }}>
        {ribbons.map((r) => (
          <path key={r.key} d={r.d} fill="none" stroke={r.color}
            strokeWidth={r.th} strokeOpacity={hov ? (r.hl ? 0.55 : 0.12) : 0.26}
            style={{ cursor: onLink ? 'pointer' : 'default', transition: 'stroke-opacity .12s' }}
            onMouseEnter={() => setHov(r.key)} onMouseLeave={() => setHov(null)}
            onClick={() => onLink && onLink(r.l.from, r.l.to)} />
        ))}
        {leftKeys.map((k) => (
          <g key={k}>
            <rect x={colX.left} y={leftY[k]} width={nodeW} height={Math.max(2, leftH[k])} rx="2" fill={leftColor[k]} />
            <text x={colX.left - 8} y={leftY[k] + Math.max(2, leftH[k]) / 2 - 4} textAnchor="end" fontSize="11" fontWeight="700" fill={CH.ink}>{leftLabel[k]}</text>
            <text x={colX.left - 8} y={leftY[k] + Math.max(2, leftH[k]) / 2 + 9} textAnchor="end" fontSize="10.5" fill={CH.muted} fontFamily="var(--mono)">{leftTot[k]}</text>
          </g>
        ))}
        {rightKeys.map((k) => (
          <g key={k}>
            <rect x={colX.right} y={rightY[k]} width={nodeW} height={Math.max(2, rightH[k])} rx="2"
              fill={k === 'core' ? CH.core : k === 'buyout' ? CH.buyout : k === 'vc' ? CH.vc : CH.other} />
            <text x={colX.right + nodeW + 8} y={rightY[k] + Math.max(2, rightH[k]) / 2 - 4} fontSize="11" fontWeight="700" fill={CH.ink}>{rightLabel[k]}</text>
            <text x={colX.right + nodeW + 8} y={rightY[k] + Math.max(2, rightH[k]) / 2 + 9} fontSize="10.5" fill={CH.muted} fontFamily="var(--mono)">{rightTot[k]}</text>
          </g>
        ))}
      </svg>
    </div>
  );
}

function ChartLegend({ items }) {
  return (
    <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap', marginTop: 4 }}>
      {items.map((it) => (
        <div key={it.label} style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--ink-muted)', fontWeight: 600 }}>
          <span style={{ width: 11, height: 11, borderRadius: 3, background: it.color, display: 'inline-block',
            ...(it.dash ? { background: 'none', borderTop: `2px dashed ${it.color}`, height: 0, width: 14, borderRadius: 0 } : {}) }}></span>
          {it.label}
        </div>
      ))}
    </div>
  );
}

Object.assign(window, { StackedBar, AreaLine, SeenOutcomeFlow, ChartLegend, CH });
