/* Sourcing visualization - ONE schematic, 5 central-database treatments.
   Shared system:
     · 12 anonymous data-source circles, grouped into named categories
       (LinkedIn & Google Maps · industry-specific · custom scrapers · OSINT)
     · each source feeds the core via a dotted line that drifts very slowly inward
     · 4 concentric PROCESSING LAYERS (match · dedupe · suppress · filter) - soft
       beige rings that fade out the farther they sit from the centre
     · funnel record-counts on each layer; one TAM database out the bottom
   The 5 variants differ only in how the central database core is drawn:
     a Pixel (slowly self-animating) · b Vault · c Aperture · d Lattice · e Cluster
   Exposes window.SourcingViz. */
const { useState: useStateSV, useEffect: useEffectSV, useRef: useRefSV } = React;
const SD = window.SD;
const MUL = window.ABM.mulberry;

/* ---------------- geometry ---------------- */
const CX = 500, CY = 320, RCORE = 66, SRCR = 244;
const RING_R = [218, 180, 142, 104];          // MATCH · DEDUPE · SUPPRESS · FILTER (outer→inner)
const RING_OPAC = [0.02, 0.045, 0.075, 0.11];   // extremely soft beige rings - inner barely there, outer near-invisible
const RING_BEIGE = "74,58,42";                 // warm brown → reads as taupe/beige on cream
const GAP = 70;                                // open wedge at the bottom (for the output)
function P(r, aDeg) { const a = aDeg * Math.PI / 180; return [CX + Math.cos(a) * r, CY + Math.sin(a) * r]; }
function srcAngle(i) { return (90 + GAP / 2) + (i + 0.5) * (360 - GAP) / 12; }

/* core emerald, mixed toward grey by f (used only inside the database cores) */
const EM = [0, 109, 78], GREY = [168, 174, 168];
function toneRgb(f) { const m = (a, b) => Math.round(a + (b - a) * f); return [m(EM[0], GREY[0]), m(EM[1], GREY[1]), m(EM[2], GREY[2])]; }
function tone(f) { const c = toneRgb(f); return `rgb(${c[0]},${c[1]},${c[2]})`; }

/* deterministic, lightly-scattered source position */
function jit(rng, a) { return (rng() * 2 - 1) * a; }
function srcPos(i) {
  const base = srcAngle(i), rng = MUL(i * 131 + 11);
  const rr = SRCR + jit(rng, 11), aa = base + jit(rng, 1.8);
  const [x, y] = P(rr, aa);
  return { x, y, base };
}

/* ---------------- a clean, anonymous source circle (uniform size) ---------------- */
function SourceShape({ i }) {
  const { x, y } = srcPos(i);
  const fillEm = MUL(i * 131 + 60)() < 0.45;
  return <circle cx={x} cy={y} r={11.5} fill={fillEm ? "rgba(0,109,78,0.13)" : "var(--abm-card)"} stroke="rgba(7,19,29,0.55)" strokeWidth="1.4" />;
}

/* one dotted line, drifting very slowly toward the centre */
function InArrow({ i }) {
  const { x, y } = srcPos(i);
  const dx = CX - x, dy = CY - y, len = Math.hypot(dx, dy) || 1, ux = dx / len, uy = dy / len;
  const sx = x + ux * 15, sy = y + uy * 15, ex = CX - ux * (RCORE + 7), ey = CY - uy * (RCORE + 7);
  return <line className="sv-drip" x1={sx} y1={sy} x2={ex} y2={ey} stroke="rgba(7,19,29,0.2)" strokeWidth="1.4" strokeLinecap="round" />;
}

/* loose category titles near each region (no explicit grouping / brackets) */
function GroupLabels() {
  let gi = 0;
  return (
    <g>
      {SD.dbSourceGroups.map((g, k) => {
        const start = gi, end = gi + g.n - 1; gi += g.n;
        const mid = (srcAngle(start) + srcAngle(end)) / 2;
        const [tx, ty] = P(SRCR + 78, mid);
        return (
          <text key={k} x={tx} y={ty} textAnchor="middle" className="mono" style={{ fill: "var(--abm-muted)", fontSize: 10 }}>
            {g.lines.map((ln, j) => <tspan key={j} x={tx} dy={j === 0 ? (g.lines.length > 1 ? -3 : 4) : 12}>{ln}</tspan>)}
          </text>
        );
      })}
    </g>
  );
}

/* ---------------- the 5 central cores ---------------- */
/* a · PIXEL - self-animating: one pixel at a time slowly darkens ~28% and fades back */
function CorePixel() {
  const cellsRef = useRefSV(null);
  if (!cellsRef.current) {
    const rnd = MUL(21), n = 11, cell = (RCORE * 2 - 8) / n, x0 = CX - RCORE + 4, y0 = CY - RCORE + 4, arr = [];
    for (let r = 0; r < n; r++) for (let c = 0; c < n; c++) {
      const cx = x0 + c * cell + cell / 2, cy = y0 + r * cell + cell / 2, v = rnd();
      if (Math.hypot(cx - CX, cy - CY) > RCORE - 5 || v < 0.12) continue;
      const baseCol = v < 0.2 ? [255, 160, 141] : toneRgb(0.04 + v * 0.34);
      arr.push({ x: x0 + c * cell + 0.7, y: y0 + r * cell + 0.7, w: cell - 1.4, base: baseCol });
    }
    cellsRef.current = arr;
  }
  const cells = cellsRef.current;
  const [active, setActive] = useStateSV(-1);
  useEffectSV(() => {
    const id = setInterval(() => setActive(Math.floor(Math.random() * cells.length)), 850);
    return () => clearInterval(id);
  }, []);
  return (
    <g clipPath="url(#coreClip)">
      {cells.map((c, idx) => {
        const col = idx === active ? c.base.map((v) => Math.round(v * 0.72)) : c.base;
        return <rect key={idx} x={c.x} y={c.y} width={c.w} height={c.w} fill={`rgb(${col[0]},${col[1]},${col[2]})`} style={{ transition: "fill 0.75s ease" }} />;
      })}
    </g>
  );
}
function CoreVault() {
  const rx = 42, ry = 13, top = CY - 28, bot = CY + 28;
  return (
    <g clipPath="url(#coreClip)">
      <path d={`M ${CX - rx} ${top} L ${CX - rx} ${bot} A ${rx} ${ry} 0 0 0 ${CX + rx} ${bot} L ${CX + rx} ${top} Z`} fill="#00583E" />
      {[-9, 4, 17].map((dy, i) => <path key={i} d={`M ${CX - rx} ${CY + dy} A ${rx} ${ry} 0 0 0 ${CX + rx} ${CY + dy}`} fill="none" stroke="rgba(255,255,255,0.22)" strokeWidth="1" />)}
      <line x1={CX - rx} y1={top} x2={CX - rx} y2={bot} stroke="#07131D" strokeWidth="1.3" />
      <line x1={CX + rx} y1={top} x2={CX + rx} y2={bot} stroke="#07131D" strokeWidth="1.3" />
      <path d={`M ${CX - rx} ${bot} A ${rx} ${ry} 0 0 0 ${CX + rx} ${bot}`} fill="none" stroke="#07131D" strokeWidth="1.3" />
      <ellipse cx={CX} cy={top} rx={rx} ry={ry} fill="#0A7A57" stroke="#07131D" strokeWidth="1.3" />
      <ellipse cx={CX} cy={top} rx={rx * 0.5} ry={ry * 0.5} fill="none" stroke="rgba(255,255,255,0.32)" strokeWidth="1" />
    </g>
  );
}
function CoreAperture() {
  return (
    <g clipPath="url(#coreClip)">
      {[60, 50, 40, 30, 20].map((r, i) => <circle key={r} cx={CX} cy={CY} r={r} fill="none" stroke={tone(0.04 + i * 0.16)} strokeWidth="1.3" />)}
      <g>
        <animateTransform attributeName="transform" type="rotate" from={`0 ${CX} ${CY}`} to={`360 ${CX} ${CY}`} dur="36s" repeatCount="indefinite" />
        {Array.from({ length: 12 }).map((_, i) => { const a = i / 12 * Math.PI * 2; return <line key={i} x1={CX + Math.cos(a) * 60} y1={CY + Math.sin(a) * 60} x2={CX + Math.cos(a) * 50} y2={CY + Math.sin(a) * 50} stroke={tone(0.32)} strokeWidth="1.4" />; })}
      </g>
      <circle cx={CX} cy={CY} r="10" fill="#006D4E" />
      <circle cx={CX} cy={CY} r="3.6" fill="var(--abm-paper)" />
    </g>
  );
}
function hexPts(cx, cy, r) { let p = ""; for (let k = 0; k < 6; k++) { const a = k / 6 * Math.PI * 2 + Math.PI / 6; p += `${cx + Math.cos(a) * r},${cy + Math.sin(a) * r} `; } return p.trim(); }
function CoreLattice() {
  const R = 10, dx = R * 1.73, dy = R * 1.5, out = [];
  for (let row = -4; row <= 4; row++) for (let col = -4; col <= 4; col++) {
    const cx = CX + col * dx + (row & 1 ? dx / 2 : 0), cy = CY + row * dy;
    if (Math.hypot(cx - CX, cy - CY) > RCORE - 7) continue;
    const fill = (row + col + 16) % 3 === 0 ? tone(0.1) : ((row + col + 16) % 3 === 1 ? "rgba(0,109,78,0.12)" : "none");
    out.push(<polygon key={row + "-" + col} points={hexPts(cx, cy, R - 1.3)} fill={fill} stroke="rgba(0,88,62,0.5)" strokeWidth="1" />);
  }
  return <g clipPath="url(#coreClip)">{out}</g>;
}
function CoreCluster() {
  const rnd = MUL(8), dots = [], pts = [];
  for (let i = 0; i < 84; i++) { const a = rnd() * Math.PI * 2, rr = Math.sqrt(rnd()) * (RCORE - 7); pts.push([CX + Math.cos(a) * rr, CY + Math.sin(a) * rr, rnd()]); }
  pts.forEach((p, i) => { if (i % 7 === 0 && i > 0) dots.push(<line key={"l" + i} x1={p[0]} y1={p[1]} x2={pts[i - 1][0]} y2={pts[i - 1][1]} stroke="rgba(7,19,29,0.16)" strokeWidth="0.8" />); });
  pts.forEach((p, i) => dots.push(<circle key={i} cx={p[0]} cy={p[1]} r={1.4 + p[2] * 2.2} fill={p[2] < 0.4 ? "#006D4E" : "rgba(7,19,29,0.55)"} />));
  return <g clipPath="url(#coreClip)">{dots}</g>;
}
const CORES = { a: CorePixel, b: CoreVault, c: CoreAperture, d: CoreLattice, e: CoreCluster };

/* ---------------- the schematic ---------------- */
function Schematic({ kind }) {
  const Core = CORES[kind];
  const barTop = 540, coreBottom = CY + RCORE;
  return (
    <div className="sv-frame" style={{ height: 640 }}>
      <span className="sv-corner tl" /><span className="sv-corner tr" /><span className="sv-corner bl" /><span className="sv-corner br" />
      <svg className="sv-svg" viewBox="0 0 1000 640" preserveAspectRatio="xMidYMid meet">
        <defs><clipPath id="coreClip"><circle cx={CX} cy={CY} r={RCORE - 3} /></clipPath></defs>

        {/* header */}
        {Array.from({ length: 21 }).map((_, i) => <line key={"g" + i} className="hair-2" x1={40 + i * 46} y1="28" x2={40 + i * 46} y2="34" />)}
        <line className="hair-2" x1="40" y1="31" x2="960" y2="31" />
        <text className="mono" x="40" y="21">FIG.01 - CENTRAL DATABASE · SOURCING SCHEMA</text>
        <text className="mono" x="960" y="21" textAnchor="end">12 SOURCES · 4 LAYERS · 1 TAM</text>

        {/* faint beige radial spokes (core → inner layer) */}
        {Array.from({ length: 36 }).map((_, i) => { const a = i / 36 * Math.PI * 2, p1 = [CX + Math.cos(a) * (RCORE + 4), CY + Math.sin(a) * (RCORE + 4)], p2 = [CX + Math.cos(a) * (RING_R[3] - 4), CY + Math.sin(a) * (RING_R[3] - 4)]; return <line key={i} x1={p1[0]} y1={p1[1]} x2={p2[0]} y2={p2[1]} stroke={`rgba(${RING_BEIGE},0.07)`} strokeWidth="1" />; })}

        {/* concentric PROCESSING LAYERS - soft beige, fading outward */}
        {RING_R.map((r, i) => (
          <g key={r}>
            <circle cx={CX} cy={CY} r={r} fill="none" stroke={`rgba(${RING_BEIGE},${RING_OPAC[i]})`} strokeWidth={i === 3 ? 1.7 : 1.4} />
            {i === 0 && Array.from({ length: 72 }).map((_, k) => { const a = k / 72 * Math.PI * 2; return <line key={k} x1={CX + Math.cos(a) * r} y1={CY + Math.sin(a) * r} x2={CX + Math.cos(a) * (r + 6)} y2={CY + Math.sin(a) * (r + 6)} stroke={`rgba(${RING_BEIGE},0.05)`} strokeWidth="1" />; })}
          </g>
        ))}

        {/* one slow rotating dashed beige ring for life */}
        <circle cx={CX} cy={CY} r={161} fill="none" stroke={`rgba(${RING_BEIGE},0.1)`} strokeWidth="1.2" strokeDasharray="3 10">
          <animateTransform attributeName="transform" type="rotate" from={`0 ${CX} ${CY}`} to={`360 ${CX} ${CY}`} dur="60s" repeatCount="indefinite" />
        </circle>

        {/* dotted drip lines IN, then the source circles + group titles on top */}
        {SD.dbSources.map((s, i) => <InArrow key={"ar" + i} i={i} />)}
        {SD.dbSources.map((s, i) => <SourceShape key={s.id} i={i} />)}
        <GroupLabels />

        {/* layer labels, stacked on the (clear) top axis - name + funnel count */}
        {SD.dbLayers.map((L, i) => {
          const y = CY - RING_R[i];
          return (
            <g key={L.id}>
              <rect x={CX - 38} y={y - 12} width="76" height="24" fill="var(--abm-paper)" />
              <text x={CX} y={y - 1} textAnchor="middle" style={{ fontFamily: "var(--abm-mono)", fontSize: 9, letterSpacing: "0.1em", fontWeight: 600, fill: "var(--abm-ink)" }}>{L.label}</text>
              <text x={CX} y={y + 9} textAnchor="middle" style={{ fontFamily: "var(--abm-mono)", fontSize: 8, letterSpacing: "0.04em", fill: "var(--abm-faint)" }}>{L.count}</text>
            </g>
          );
        })}

        {/* CENTRAL DATABASE core */}
        <Core />
        <circle cx={CX} cy={CY} r={RCORE} fill="none" stroke="rgba(7,19,29,0.4)" strokeWidth="1.3" />
        <rect x={CX - 62} y={CY - RCORE - 22} width="124" height="16" fill="var(--abm-paper)" />
        <text x={CX} y={CY - RCORE - 10} textAnchor="middle" className="mono-em" style={{ fontWeight: 600 }}>CENTRAL DATABASE</text>

        {/* output → TAM database (dashed, animated, no box) */}
        <line className="sv-drip" x1={CX} y1={coreBottom} x2={CX} y2={barTop} stroke="var(--abm-ember)" strokeWidth="2" strokeLinecap="round" opacity="0.6" />
        <line x1={CX} y1={barTop + 5} x2={CX - 5.5} y2={barTop - 6} stroke="var(--abm-ember)" strokeWidth="2" strokeLinecap="round" opacity="0.6" />
        <line x1={CX} y1={barTop + 5} x2={CX + 5.5} y2={barTop - 6} stroke="var(--abm-ember)" strokeWidth="2" strokeLinecap="round" opacity="0.6" />
        <text x={CX} y={barTop + 38} textAnchor="middle" style={{ fontFamily: "var(--abm-mono)", fontSize: 40, fontWeight: 700, letterSpacing: "-0.01em", fill: "var(--abm-ember)" }}>{SD.dbOut.count}</text>
        <text x={CX} y={barTop + 58} textAnchor="middle" style={{ fontFamily: "var(--abm-mono)", fontSize: 9.5, letterSpacing: "0.18em", fill: "var(--abm-muted)" }}>ACCOUNTS · TAM DATABASE</text>
      </svg>
      <div className="sv-cap"><span className="abm-tag" style={{ color: "var(--abm-faint)" }}>12 SOURCES → 4 PROCESSING LAYERS → 1 TAM DATABASE</span></div>
    </div>
  );
}

/* ---------------- switcher (5 central-core treatments) ---------------- */
function SourcingViz() {
  const [mode, setMode] = useStateSV("a");
  const opts = [["a", "Pixel"], ["b", "Vault"], ["c", "Aperture"], ["d", "Lattice"], ["e", "Cluster"]];
  return (
    <div>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, marginBottom: 14, flexWrap: "wrap" }}>
        <span className="abm-tag" style={{ color: "var(--abm-faint)" }}>DATABASE SCHEMATIC · 5 CENTRAL-CORE TREATMENTS</span>
        <div className="sv-seg">
          {opts.map(([k, l]) => <button key={k} className={mode === k ? "on" : ""} onClick={() => setMode(k)}>{l}</button>)}
        </div>
      </div>
      <Schematic kind={mode} />
    </div>
  );
}

Object.assign(window, { SourcingViz, Schematic });
