// seed-lattice.jsx — The deterministic seed system, without dilution.
//
// Strategic move: every derivative seed in the entire brand surface comes
// from the parent brand seed via a deterministic derivation function.
// Adding new uses NEVER dilutes — it elaborates. Like a fractal.
//
//                 BRAND_SEEDS.colorSeed (parent)
//                /         |         |         \
//          brand:logo  brand:patt  brand:glyph  brand:font
//                |
//   ┌────────────┼─────────────┬─────────────┬──────────────┐
//   │            │             │             │              │
//  Council    TradeXchange  QuickStart   Onboarding     [future]
//   │            │             │
//   │            ├── per-order:tx                  (one sigil per trade)
//   │            ├── per-day:nonce                 (one seal per heartbeat)
//   │            └── per-customer:domain           (one founding mark)
//   │
//   ├── per-NFT:tokenId                            (each agent's sigil)
//   ├── per-slash:tx                               (each slash event)
//   └── per-session:sessionId                      (subtle visitor variance)
//
// Same input → same artifact, forever. Different input → guaranteed different.

// ── Hashing ───────────────────────────────────────────────────
// Tiny string-to-32bit hash. Stable, fast, deterministic.
function hash32(str) {
  let h = 2166136261 >>> 0;       // FNV offset basis
  for (let i = 0; i < str.length; i++) {
    h ^= str.charCodeAt(i);
    h = Math.imul(h, 16777619);   // FNV prime
  }
  return h >>> 0;
}

// Convert any hex string (tx hash, address) to a 32-bit seed.
function seedFromHex(hex) {
  if (!hex) return 0;
  const clean = hex.replace(/^0x/i, '').slice(0, 12);
  return parseInt(clean, 16) >>> 0;
}

// ── Derivation ────────────────────────────────────────────────
// Child seed = mix(parent, scope). The parent's information is fully
// preserved; the scope adds independent entropy. Adding scopes never
// reduces the parent's information content — that's the no-dilution property.
function deriveSeed(parent, scope) {
  const p = (typeof parent === 'string') ? seedFromHex(parent) : (parent >>> 0);
  const s = hash32(String(scope));
  // Mix: rotate parent by hash, xor, multiply, rotate again.
  let n = p ^ s;
  n = Math.imul(n, 2654435761);
  n = ((n << 13) | (n >>> 19)) >>> 0;
  n ^= Math.imul(s, 1597334677);
  n = ((n << 5)  | (n >>> 27)) >>> 0;
  return n >>> 0;
}

// ── PRNG ──────────────────────────────────────────────────────
// Seeded LCG. Returns a function that yields floats in [0, 1).
function seedRng(seed) {
  let n = (seed >>> 0) || 1;
  return () => {
    n = (Math.imul(n, 1664525) + 1013904223) >>> 0;
    return n / 0xFFFFFFFF;
  };
}

// ── Brand parent seed ────────────────────────────────────────
// Always derive everything from this. Pulled from brand-tokens.css.
// If brand-mark.jsx is loaded, use BRAND_SEEDS.colorSeed.
const BRAND_PARENT = (typeof BRAND_SEEDS !== 'undefined' && BRAND_SEEDS.colorSeed)
  ? Math.floor(BRAND_SEEDS.colorSeed) >>> 0
  : 1779342991571 >>> 0;

// ── Scope helpers ─────────────────────────────────────────────
// Every property of the brand (council, tradexchange, quickstart, etc) gets
// a derived seed. Per-entity helpers further derive into per-order,
// per-day, per-NFT scopes — provably descended from the parent.
function subBrandSeed(name)             { return deriveSeed(BRAND_PARENT, 'subbrand:' + name); }
const COUNCIL_SEED  = subBrandSeed('council');
const TX_SEED       = subBrandSeed('tradexchange');
const QUICKSTART_SEED = subBrandSeed('quickstart');

function orderSeed(proof, block)        { return deriveSeed(TX_SEED, 'order:' + proof + ':' + block); }
function daySeed(nonceHex)              { return deriveSeed(COUNCIL_SEED, 'day:' + nonceHex); }
function slashSeed(tx)                  { return deriveSeed(COUNCIL_SEED, 'slash:' + tx); }
function customerSeed(domain, ts)       { return deriveSeed(QUICKSTART_SEED, 'cust:' + domain + ':' + ts); }
function sessionSeed(sessionId)         { return deriveSeed(BRAND_PARENT, 'session:' + sessionId); }
function epochSeed(year, quarter)       { return deriveSeed(BRAND_PARENT, 'epoch:' + year + 'Q' + quarter); }

// ── SeedSigil — one universal renderer ───────────────────────
// Renders a Synapse-mode generative mark from a numeric seed.
// Used by: order receipts, daily seals, slash events, founding marks, etc.
// Visual differs by `variant`:
//   - 'mark'  → minimal, compact: ring + 3 lines + center (good for inline)
//   - 'sigil' → standard:        ring + constellation + glyph (default)
//   - 'seal'  → ornate:          double ring + 8 lines + center pip (for receipts)
function SeedSigil({ seed, size = 48, colors, variant = 'sigil' }) {
  const rng    = seedRng(seed);
  const cx     = size / 2;
  const cy     = size / 2;
  const outerR = size * 0.42;
  const C = {
    ring:  (colors && colors.ring)  || '#a334f3',
    field: (colors && colors.field) || '#42a023',
    core:  (colors && colors.core)  || (colors && colors.ring) || '#e72020',
  };

  // Variant tunables — same generator, three different visual densities.
  const cfg = {
    mark:  { nodes:  6, lines: 3,  spokes: 0,  dashed: false, innerRing: false, glyph: 'dot' },
    sigil: { nodes: 10, lines: 8,  spokes: 5,  dashed: true,  innerRing: true,  glyph: 'poly' },
    seal:  { nodes: 14, lines: 12, spokes: 7,  dashed: true,  innerRing: true,  glyph: 'crosshair' },
  }[variant] || { nodes: 10, lines: 8, spokes: 5, dashed: true, innerRing: true, glyph: 'poly' };

  // Sample N constellation nodes around the ring.
  const nodes = Array.from({ length: cfg.nodes }).map((_, i) => {
    const a   = (i / cfg.nodes) * Math.PI * 2 + rng() * 0.6;
    const rad = outerR * (0.55 + rng() * 0.40);
    return { x: cx + Math.cos(a) * rad, y: cy + Math.sin(a) * rad };
  });

  // Choose constellation lines deterministically.
  const lineIdx = [];
  for (let i = 0; i < cfg.lines; i++) {
    const a = Math.floor(rng() * nodes.length);
    let b   = Math.floor(rng() * nodes.length);
    if (a === b) b = (b + 1) % nodes.length;
    lineIdx.push([a, b]);
  }

  // Inner polygon points (for sigil variant).
  const sides = 3 + Math.floor(rng() * 5);    // 3–7 sides
  const rot   = rng() * Math.PI * 2;
  const inR   = size * 0.16;
  const poly  = Array.from({ length: sides }).map((_, i) => {
    const a = (i / sides) * Math.PI * 2 + rot;
    return `${cx + Math.cos(a) * inR},${cy + Math.sin(a) * inR}`;
  }).join(' ');

  const sw = Math.max(0.8, size * 0.022);

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}
         style={{ display: 'block' }}
         role="img" aria-label="generative seal">
      {/* outer ring */}
      <circle cx={cx} cy={cy} r={outerR}
        fill="none" stroke={C.ring}
        strokeWidth={sw}
        strokeDasharray={cfg.dashed ? `${size * 0.08} ${size * 0.04}` : 'none'}
        opacity="0.95"/>

      {/* inner faint ring (sigil/seal only) */}
      {cfg.innerRing && (
        <circle cx={cx} cy={cy} r={outerR * 0.66} fill="none"
          stroke={C.ring} strokeWidth={sw * 0.55} opacity="0.32"/>
      )}

      {/* constellation lines — field color */}
      {lineIdx.map(([a, b], i) => (
        <line key={'l' + i}
          x1={nodes[a].x} y1={nodes[a].y}
          x2={nodes[b].x} y2={nodes[b].y}
          stroke={C.field} strokeWidth={sw * 0.85}
          opacity={i % 2 === 0 ? 0.36 : 0.20}
          strokeLinecap="round"/>
      ))}

      {/* radiating spokes */}
      {cfg.spokes > 0 && Array.from({ length: cfg.spokes }).map((_, i) => {
        const a = (i / cfg.spokes) * Math.PI * 2;
        const x1 = cx + Math.cos(a) * (outerR * 0.55);
        const y1 = cy + Math.sin(a) * (outerR * 0.55);
        const x2 = cx + Math.cos(a) * (outerR * 0.74);
        const y2 = cy + Math.sin(a) * (outerR * 0.74);
        return <line key={'sp'+i} x1={x1} y1={y1} x2={x2} y2={y2}
          stroke={C.ring} strokeWidth={sw * 0.7} opacity="0.55"/>;
      })}

      {/* glyph */}
      {cfg.glyph === 'poly' && (
        <polygon points={poly}
          fill={C.core} fillOpacity="0.30"
          stroke={C.core} strokeWidth={sw * 1.1}/>
      )}
      {cfg.glyph === 'crosshair' && (
        <g>
          <circle cx={cx} cy={cy} r={size * 0.10}
            fill="none" stroke={C.core} strokeWidth={sw}/>
          <line x1={cx - size*0.16} y1={cy} x2={cx + size*0.16} y2={cy}
            stroke={C.core} strokeWidth={sw}/>
          <line x1={cx} y1={cy - size*0.16} x2={cx} y2={cy + size*0.16}
            stroke={C.core} strokeWidth={sw}/>
        </g>
      )}
      {cfg.glyph === 'dot' && (
        <circle cx={cx} cy={cy} r={size * 0.08} fill={C.core}/>
      )}

      {/* center pip */}
      <circle cx={cx} cy={cy} r={size * 0.030} fill={C.ring}/>
    </svg>
  );
}

Object.assign(window, {
  hash32, seedFromHex, deriveSeed, seedRng,
  BRAND_PARENT, COUNCIL_SEED, TX_SEED, QUICKSTART_SEED,
  subBrandSeed,
  orderSeed, daySeed, slashSeed, customerSeed, sessionSeed, epochSeed,
  SeedSigil,
});
