// Generative SVG visuals for MandateWorks
// Each card visual is a small generative diagram using brand tokens.

const Mark = ({size = 28}) => (
  <span className="mw-mark" style={{width: size, height: size}}>
    <svg viewBox="0 0 28 28" fill="none">
      <rect x="1.5" y="1.5" width="25" height="25" stroke="currentColor" strokeWidth="1.25" />
      <line x1="6" y1="22" x2="22" y2="6" stroke="var(--volt)" strokeWidth="2.25" strokeLinecap="square" />
    </svg>
  </span>
);

// ───── GLYPH SWAP — S02 — volt headline word cycles through meanings ─────
const GlyphSwap = ({words, interval = 2400}) => {
  const [i, setI] = React.useState(0);
  const [prev, setPrev] = React.useState(null);
  React.useEffect(() => {
    const t = setInterval(() => {
      setPrev(i);
      setI((x) => (x + 1) % words.length);
      setTimeout(() => setPrev(null), 600);
    }, interval);
    return () => clearInterval(t);
  }, [i, words.length, interval]);
  // anchor sized to longest word so layout doesn't jump
  const longest = words.reduce((a, b) => (b.length > a.length ? b : a), "");
  return (
    <span className="glyph-slot">
      <span className="anchor">{longest}</span>
      {prev !== null && (
        <span key={`p-${prev}`} className="word in out">{words[prev]}</span>
      )}
      <span key={`c-${i}`} className="word in">{words[i]}</span>
    </span>
  );
};

// ───── HERO CANVAS — persona constellation w/ live ping ─────
const HeroCanvas = () => {
  const dots = React.useMemo(() => {
    const arr = [];
    const seed = (i) => Math.sin(i * 12.9898) * 43758.5453;
    const rand = (i) => seed(i) - Math.floor(seed(i));
    for (let i = 0; i < 130; i++) {
      arr.push({
        cx: 60 + rand(i + 1) * 460,
        cy: 60 + rand(i + 11) * 460,
        r: 1 + Math.floor(rand(i + 23) * 3),
        v: rand(i + 41) > 0.85,
      });
    }
    return arr;
  }, []);
  return (
    <svg className="hero-canvas" viewBox="0 0 580 580" fill="none">
      <defs>
        <pattern id="dots" width="14" height="14" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r=".7" fill="#DCD7CB" />
        </pattern>
        <radialGradient id="halo" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="#2E2BFF" stopOpacity=".18" />
          <stop offset="60%" stopColor="#2E2BFF" stopOpacity="0" />
        </radialGradient>
      </defs>
      <circle cx="290" cy="290" r="280" fill="url(#halo)" />
      <rect width="580" height="580" fill="url(#dots)" opacity=".5" />
      {/* concentric rings */}
      {[260, 200, 140, 80].map((r, i) => (
        <circle key={i} cx="290" cy="290" r={r} stroke="#0E1116" strokeWidth=".4" fill="none" opacity={i === 0 ? 1 : 0.35} />
      ))}
      {/* spokes */}
      {Array.from({length: 12}).map((_, i) => {
        const a = (i / 12) * Math.PI * 2;
        return (
          <line key={i} x1={290 + Math.cos(a) * 80} y1={290 + Math.sin(a) * 80} x2={290 + Math.cos(a) * 260} y2={290 + Math.sin(a) * 260} stroke="#DCD7CB" strokeWidth=".5" />
        );
      })}
      {/* persona dots */}
      {dots.map((d, i) => (
        <circle key={i} cx={d.cx} cy={d.cy} r={d.r} fill={d.v ? "#2E2BFF" : "#0E1116"} opacity={d.v ? 1 : 0.7} />
      ))}
      {/* highlight cross */}
      <g>
        <circle cx="290" cy="290" r="6" fill="#2E2BFF" />
        <circle cx="290" cy="290" r="14" stroke="#2E2BFF" strokeWidth="1.2" fill="none">
          <animate attributeName="r" from="6" to="32" dur="2.6s" repeatCount="indefinite" />
          <animate attributeName="opacity" from="1" to="0" dur="2.6s" repeatCount="indefinite" />
        </circle>
      </g>
      {/* axis labels */}
      <text x="20" y="28" fontFamily="JetBrains Mono" fontSize="9" letterSpacing="2" fill="#6B7180">SIM /04 21 · N=12,480</text>
      <text x="20" y="568" fontFamily="JetBrains Mono" fontSize="9" letterSpacing="2" fill="#6B7180">PERSONAS · 7 SEGMENTS</text>
      <text x="430" y="568" fontFamily="JetBrains Mono" fontSize="9" letterSpacing="2" fill="#6B7180">LIVE</text>
      <circle cx="424" cy="565" r="3" fill="#00C281" />
    </svg>
  );
};

// ───── PLATFORM VISUALS ─────
const VisForecast = () => (
  <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
    <line x1="0" y1="120" x2="280" y2="120" stroke="#0E1116" strokeWidth=".6" />
    <line x1="20" y1="0" x2="20" y2="120" stroke="#DCD7CB" strokeWidth=".5" />
    {/* baseline */}
    <path d="M20 100 Q60 90 100 80 T180 65 T260 50" stroke="#6B7180" strokeWidth="1" strokeDasharray="2 3" fill="none" />
    {/* forecast bands */}
    <path d="M20 100 Q60 80 100 70 T180 40 T260 25 L260 70 Q200 70 160 75 T100 90 T20 100 Z" fill="#2E2BFF" opacity=".12" />
    <path d="M20 100 Q60 88 100 78 T180 55 T260 38" stroke="#2E2BFF" strokeWidth="1.6" fill="none" />
    {/* persona dots */}
    {[[40, 92], [80, 78], [120, 70], [160, 58], [200, 48], [240, 36]].map(([x, y], i) => (
      <g key={i}>
        <circle cx={x} cy={y} r="3" fill="#2E2BFF" />
        <circle cx={x} cy={y} r="6" stroke="#2E2BFF" strokeWidth=".5" fill="none" />
      </g>
    ))}
    <text x="22" y="14" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">VOTE SHARE · WHAT-IF</text>
    <text x="240" y="118" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1">D-30</text>
  </svg>
);

const VisCadre = () => (
  <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
    {/* training matrix */}
    {Array.from({length: 6}).map((_, r) =>
      Array.from({length: 14}).map((_, c) => {
        const filled = (r * 7 + c * 3) % 5 < 3;
        return (
          <rect key={`${r}-${c}`} x={20 + c * 18} y={20 + r * 16} width="14" height="12" fill={filled ? (c % 5 === 0 ? "#2E2BFF" : "#0E1116") : "transparent"} stroke="#0E1116" strokeWidth=".5" opacity={filled ? 1 : 0.25} />
        );
      })
    )}
    <text x="22" y="14" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">CURRICULUM · 84 MODULES</text>
    <text x="22" y="132" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">CADRE COMPLETION 71%</text>
  </svg>
);

const VisSentinel = () => {
  // S07 — Threat radar: rotating sweep + intermittent blips
  const [blips, setBlips] = React.useState([]);
  const sweepRef = React.useRef(null);
  React.useEffect(() => {
    let id = 0;
    const t = setInterval(() => {
      const a = Math.random() * Math.PI * 2;
      const r = 12 + Math.random() * 56;
      const cx = 140 + Math.cos(a) * r;
      const cy = 70 + Math.sin(a) * r * 0.85;
      const isAlert = Math.random() > 0.72;
      const myId = ++id;
      setBlips((b) => [...b, {id: myId, cx, cy, alert: isAlert}]);
      setTimeout(() => setBlips((b) => b.filter((x) => x.id !== myId)), 1600);
    }, 850);
    return () => clearInterval(t);
  }, []);
  return (
    <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
      <defs>
        <radialGradient id="sen-rg" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="#2E2BFF" stopOpacity=".18" />
          <stop offset="100%" stopColor="#2E2BFF" stopOpacity="0" />
        </radialGradient>
        <linearGradient id="sen-sweep" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#2E2BFF" stopOpacity="0" />
          <stop offset="100%" stopColor="#2E2BFF" stopOpacity=".7" />
        </linearGradient>
      </defs>
      <ellipse cx="140" cy="70" rx="60" ry="52" fill="url(#sen-rg)" />
      <ellipse cx="140" cy="70" rx="60" ry="52" fill="none" stroke="#0E1116" strokeWidth=".5" />
      <ellipse cx="140" cy="70" rx="40" ry="34" fill="none" stroke="#DCD7CB" strokeWidth=".5" />
      <ellipse cx="140" cy="70" rx="20" ry="17" fill="none" stroke="#DCD7CB" strokeWidth=".5" />
      <line x1="140" y1="18" x2="140" y2="122" stroke="#DCD7CB" strokeWidth=".4" />
      <line x1="80" y1="70" x2="200" y2="70" stroke="#DCD7CB" strokeWidth=".4" />
      <g ref={sweepRef} style={{transformOrigin: "140px 70px", animation: "sen-sweep 3.6s linear infinite"}}>
        <path d="M140 70 L140 18 A60 52 0 0 1 200 70 Z" fill="url(#sen-sweep)" opacity=".7" />
      </g>
      <circle cx="140" cy="70" r="2.5" fill="#0E1116" />
      {blips.map((b) => (
        <circle key={b.id} cx={b.cx} cy={b.cy} r="2"
          fill={b.alert ? "#FF5A36" : "#2E2BFF"}
          style={{animation: "sen-blip 1.5s var(--ease) forwards"}} />
      ))}
      <text x="22" y="14" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">SENTINEL · 24H</text>
      <text x="200" y="14" fontFamily="JetBrains Mono" fontSize="8" fill="#FF5A36" letterSpacing="1.5">▲ LIVE</text>
    </svg>
  );
};

const VisCounter = () => {
  // Continuous scrape → flag → assign rebuttal
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const t = setInterval(() => setTick((x) => x + 1), 1800);
    return () => clearInterval(t);
  }, []);
  const flagged = tick % 4 === 0;
  return (
    <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
      <text x="0" y="10" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">COUNTER · LIVE FEED</text>
      <text x="226" y="10" fontFamily="JetBrains Mono" fontSize="8" fill="#FF5A36" letterSpacing="1.5">▲ {String(2 + (tick % 5)).padStart(2, "0")} FLAGGED</text>

      {/* incoming stream */}
      {[0, 1, 2, 3].map((i) => {
        const y = 26 + i * 14;
        const isFlag = i === 1;
        return (
          <g key={i} style={{animation: `cnt-stream ${1.8}s linear infinite`, animationDelay: `${i * -0.45}s`}}>
            <rect x="0" y={y - 5} width="6" height="2" fill={isFlag ? "#FF5A36" : "#0E1116"} />
            <rect x="10" y={y - 5} width="60" height="2" fill="#DCD7CB" />
            <rect x="10" y={y - 1} width={28 + i * 8} height="2" fill="#DCD7CB" />
            {isFlag && <rect x="74" y={y - 6} width="22" height="8" fill="#FF5A36" opacity=".15" />}
            {isFlag && <text x="76" y={y + 1} fontFamily="JetBrains Mono" fontSize="6.5" fill="#FF5A36" letterSpacing="1">FALSE</text>}
          </g>
        );
      })}

      {/* arrow → response card */}
      <line x1="106" y1="55" x2="124" y2="55" stroke="#0E1116" strokeWidth=".8" markerEnd="url(#cnt-arr)" />
      <defs>
        <marker id="cnt-arr" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="5" markerHeight="5" orient="auto">
          <path d="M0 0 L10 5 L0 10 Z" fill="#0E1116" />
        </marker>
      </defs>

      {/* response card */}
      <g>
        <rect x="128" y="22" width="148" height="68" fill="#FFFFFF" stroke="#0E1116" strokeWidth=".7" />
        <text x="134" y="34" fontFamily="JetBrains Mono" fontSize="7" fill="#6B7180" letterSpacing="1.2">REBUTTAL · DRAFTED 1.2s</text>
        <rect x="134" y="40" width="120" height="2" fill="#0E1116" />
        <rect x="134" y="46" width="100" height="2" fill="#DCD7CB" />
        <rect x="134" y="52" width="112" height="2" fill="#DCD7CB" />
        <rect x="134" y="58" width="80"  height="2" fill="#DCD7CB" />
        {/* assignee chip */}
        <rect x="134" y="68" width="56" height="14" fill="#2E2BFF" />
        <text x="138" y="78" fontFamily="JetBrains Mono" fontSize="7" fill="#FFFFFF" letterSpacing="1">ASSIGN · 12</text>
        <text x="196" y="78" fontFamily="JetBrains Mono" fontSize="7" fill="#0E1116" letterSpacing="1">▸ ONE-TAP</text>
      </g>

      {/* member dots queue */}
      <text x="0" y="108" fontFamily="JetBrains Mono" fontSize="7" fill="#6B7180" letterSpacing="1.2">MEMBERS</text>
      {Array.from({length: 18}).map((_, i) => {
        const x = 56 + (i % 18) * 12;
        const active = ((tick + i) % 7) < 3;
        return (
          <circle key={i} cx={x} cy="106" r={active ? 2.4 : 1.6}
            fill={active ? "#2E2BFF" : "#DCD7CB"}
            style={{transition: "all .4s var(--ease)"}} />
        );
      })}

      <text x="0" y="130" fontFamily="JetBrains Mono" fontSize="7.5" fill="#6B7180" letterSpacing="1.5">RESPONSE TIME · 92s MEDIAN</text>
    </svg>
  );
};

const VisMandateOne = () => (
  <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
    {/* constituency map abstract */}
    <path d="M30 30 L90 25 L130 40 L160 30 L200 50 L240 40 L250 90 L210 110 L160 100 L120 115 L70 105 L40 80 Z"
      fill="#ECE8DF" stroke="#0E1116" strokeWidth=".8" />
    {/* booths */}
    {[[60, 50], [110, 70], [150, 55], [190, 80], [220, 60], [80, 85], [150, 95]].map(([x, y], i) => (
      <g key={i}>
        <circle cx={x} cy={y} r="2" fill="#0E1116" />
        <circle cx={x} cy={y} r="6" stroke="#2E2BFF" strokeWidth=".6" fill="none" opacity=".4" />
      </g>
    ))}
    {/* highlighted booth */}
    <circle cx="150" cy="55" r="3.5" fill="#2E2BFF" />
    <line x1="150" y1="55" x2="240" y2="20" stroke="#2E2BFF" strokeWidth=".5" />
    <text x="220" y="16" fontFamily="JetBrains Mono" fontSize="8" fill="#0E1116" letterSpacing="1">B-117</text>
    <text x="220" y="26" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1">+3.4%</text>
    <text x="22" y="132" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">CONSTITUENCY · 2,418 BOOTHS</text>
  </svg>
);

const VisResolve = () => {
  // S09 — SLA race: bars fill against clock with staggered start
  const [racing, setRacing] = React.useState(false);
  React.useEffect(() => {
    const start = () => {
      setRacing(false);
      setTimeout(() => setRacing(true), 80);
    };
    start();
    const t = setInterval(start, 6500);
    return () => clearInterval(t);
  }, []);
  const rows = [
    {id: "T-0421", w: 32, color: "#00C281", label: "02h ✓"},
    {id: "T-0422", w: 48, color: "#00C281", label: "06h ✓"},
    {id: "T-0423", w: 78, color: "#FFB020", label: "36h ⚠"},
    {id: "T-0424", w: 96, color: "#FF5A36", label: "71h ▲"},
    {id: "T-0425", w: 22, color: "#00C281", label: "01h ✓"},
  ];
  return (
    <svg viewBox="0 0 280 140" fill="none" width="100%" height="140">
      <text x="0" y="10" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">SLA · CITIZEN TICKETS</text>
      <text x="232" y="10" fontFamily="JetBrains Mono" fontSize="8" fill="#6B7180" letterSpacing="1.5">94.2%</text>
      {rows.map((r, i) => {
        const y = 22 + i * 20;
        const trackX = 44;
        const trackW = 196;
        const fillW = racing ? (trackW * r.w) / 100 : 0;
        return (
          <g key={r.id}>
            <text x="0" y={y + 3} fontFamily="JetBrains Mono" fontSize="7.5" fill="#6B7180" letterSpacing="1.2">{r.id}</text>
            <rect x={trackX} y={y - 3} width={trackW} height="6" fill="#ECE8DF" />
            <rect x={trackX} y={y - 3} width={fillW} height="6" fill={r.color}
              style={{transition: `width 1.6s var(--ease) ${i * 0.14}s`}} />
            <text x={trackX + trackW + 4} y={y + 3} fontFamily="JetBrains Mono" fontSize="7.5" fill={r.color} letterSpacing="1"
              style={{opacity: racing ? 1 : 0, transition: `opacity .3s var(--ease) ${i * 0.14 + 1.4}s`}}>
              {r.label}
            </text>
          </g>
        );
      })}
    </svg>
  );
};

// ───── EXPORTS ─────
Object.assign(window, {
  Mark,
  HeroCanvas,
  GlyphSwap,
  VisForecast, VisCadre, VisSentinel, VisCounter, VisMandateOne, VisResolve,
});
