// weave.jsx — Sol Madresia vivo
//
// Una estrella de 8 puntas escalonada, interpretación original de la
// gramática visual Wayuu (simetría octaval, bordes stepped, anillos
// concéntricos). No hay lattice exterior. No hay telaraña. Solo el Sol.
//
// Dos fases:
//   (1) TEJIDO (0–8 s): las puntadas aparecen en espiral desde el centro
//       hacia afuera, puntada a puntada, como si se tejiera en vivo.
//   (2) VIVO (8 s+): el Sol sigue pensando. Capas de vida superpuestas:
//       — respiración global lenta
//       — onda radial de pensamiento (heartbeat cada ~4 s) que viaja
//         desde el centro hacia afuera iluminando puntadas a su paso
//       — escaneo angular rotando en 8-fold — cells en el eje actual
//         brillan más, simula atención barriendo el tejido
//       — disparos aleatorios de celdas individuales (neuronas firing)
//       — shimmer per-cell para textura viva
//
// El Sol es la red neuronal. Cada puntada es una neurona. No se detiene.

function WovenScene() {
  const time = useTime();
  const canvasRef = React.useRef(null);
  const geom = React.useMemo(() => buildGeometry(), []);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const dpr = Math.min(window.devicePixelRatio || 1, 1.25);
    canvas.width = 1600 * dpr;
    canvas.height = 1000 * dpr;
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);
  }, []);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    draw(ctx, time, geom);
  }, [time, geom]);

  return (
    <canvas
      ref={canvasRef}
      style={{
        position: 'absolute',
        inset: 0,
        width: '100%',
        height: '100%',
        display: 'block',
      }}
    />
  );
}

// ── Geometría del Sol ──────────────────────────────────────────────────────

function buildGeometry() {
  // El Sol flota un poco arriba del centro vertical para dejar espacio
  // a la frase y la atribución Wayuu abajo.
  const CX = 800, CY = 420;
  const cellSize = 11;
  const gridRadius = 26;

  const cells = [];
  for (let gy = -gridRadius; gy <= gridRadius; gy++) {
    for (let gx = -gridRadius; gx <= gridRadius; gx++) {
      const v = solPattern(gx, gy);
      if (!v) continue;
      const r = Math.sqrt(gx * gx + gy * gy);
      const theta = Math.atan2(gy, gx);
      cells.push({
        gx, gy,
        x: CX + gx * cellSize,
        y: CY + gy * cellSize,
        r, theta,
        rPx: r * cellSize,   // radio en píxeles (para ondas radiales)
        weight: v,
        // Cada celda tiene un offset de fase para shimmer individual
        seed: Math.sin(gx * 12.9898 + gy * 78.233) * 43758.5453,
      });
    }
  }

  // Orden de tejido — espiral desde el centro. r domina, theta agrega giro.
  cells.sort((a, b) => {
    const keyA = a.r + a.theta * 0.05;
    const keyB = b.r + b.theta * 0.05;
    return keyA - keyB;
  });
  cells.forEach((c, i) => {
    c.order = i / Math.max(1, cells.length - 1);
  });

  // Radio máximo del patrón (en píxeles) — para normalizar ondas radiales
  const maxRPx = Math.max(...cells.map(c => c.rPx));

  // Polvo ambiental mínimo
  const RNG = mulberry32(17);
  const particles = [];
  for (let i = 0; i < 32; i++) {
    particles.push({
      x: RNG() * 1600,
      y: RNG() * 1000,
      r: 0.4 + RNG() * 0.9,
      speed: 0.03 + RNG() * 0.12,
      phase: RNG() * Math.PI * 2,
      dir: RNG() * Math.PI * 2,
    });
  }

  return { CX, CY, cells, cellSize, maxRPx, particles };
}

// ── Patrón del Sol ──────────────────────────────────────────────────────────
// Composición original: simetría octaval, rayos cardinales + diagonales,
// anillos concéntricos escalonados. No reproduce ningún motivo específico.

function solPattern(gx, gy) {
  const adx = Math.abs(gx);
  const ady = Math.abs(gy);
  const r = Math.sqrt(gx * gx + gy * gy);
  const diff = Math.abs(adx - ady);

  // Núcleo 3×3
  if (adx <= 1 && ady <= 1) return 1;

  // Rayos cardinales: gruesos al centro, se adelgazan
  if (r <= 9) {
    const t = Math.max(0, 2 - Math.floor(r / 3));
    if (ady <= t && adx >= 2) return 1;
    if (adx <= t && ady >= 2) return 1;
  }

  // Rayos diagonales (intermedios)
  if (r <= 7 && r >= 2) {
    const t = Math.max(0, 1 - Math.floor(r / 4));
    if (diff <= t) return 1;
  }

  // Primer anillo — triángulos escalonados entre rayos cardinales
  if (r >= 11 && r <= 14) {
    const theta = Math.atan2(gy, gx);
    const sector = ((theta / (Math.PI * 2)) * 8 + 8) % 1;
    const fromEdge = Math.min(sector, 1 - sector);
    const localR = r - 11;
    if (localR < fromEdge * 6) return 1;
  }

  // Anillo punteado intermedio a r ≈ 17
  if (r >= 16.5 && r <= 17.5) {
    const theta = Math.atan2(gy, gx);
    const pos = ((theta / (Math.PI * 2)) * 32 + 32) % 1;
    if (pos < 0.5) return 0.55;
  }

  // Anillo exterior — rombos en 8 ejes, r ≈ 21–24
  if (r >= 20 && r <= 24) {
    const theta = Math.atan2(gy, gx);
    const angle8 = ((theta / (Math.PI * 2)) * 8 + 8) % 1;
    const angleFromAxis = Math.min(angle8, 1 - angle8);
    if (angleFromAxis < 0.06) {
      const localR = Math.abs(r - 22);
      if (localR < 1.8 - angleFromAxis * 15) return 1;
    }
  }

  return 0;
}

// ── Render ──────────────────────────────────────────────────────────────────

function draw(ctx, time, geom) {
  const { CX, CY, cells, cellSize, maxRPx, particles } = geom;
  const W = 1600, H = 1000;

  ctx.save();
  // Transparente — dejamos que la corriente de código del fondo se vea a través.
  ctx.clearRect(0, 0, W, H);

  // ── FASE 1: TEJIDO (0–8s) ──
  // reveal pasa de 0 a 1 durante los primeros 8 segundos
  const revealDuration = 8;
  const reveal = smoothstep(0, revealDuration, time);
  const woven = reveal >= 0.999;
  const holdTime = Math.max(0, time - revealDuration); // tiempo en fase viva

  // ── Parámetros de vida continua (activos en fase 2) ──
  const breath = 0.5 + 0.5 * Math.sin(holdTime * 0.55);
  const breathSigned = Math.sin(holdTime * 0.55);
  const pulseScale = 1 + (woven ? breathSigned * 0.012 : 0);

  // Heartbeat: pulso radial que viaja desde el centro hacia afuera.
  // Un pulso nuevo cada ~4 s. Duración del viaje: ~2.4 s.
  const heartPeriod = 4.0;
  const heartDuration = 2.4;
  const heartElapsed = (holdTime % heartPeriod);
  const heartActive = heartElapsed < heartDuration;
  const heartProgress = heartActive ? (heartElapsed / heartDuration) : 1;
  const heartRadius = heartProgress * (maxRPx + 30);
  const heartWidth = 32;

  // Escaneo angular rotando en 8-fold
  const scanAngle = holdTime * 0.28;

  // Firing aleatorio de celdas — usa hash de tiempo+seed para determinismo suave
  // (cada celda tiene ~1% chance de firing en una ventana de 1.5s)
  const fireWindow = 1.5;
  const fireSlot = Math.floor(holdTime / fireWindow);
  const fireLocal = (holdTime % fireWindow) / fireWindow; // 0..1

  // Polvo ambiental
  for (const p of particles) {
    const drift = time * p.speed;
    const x = (p.x + Math.cos(p.dir + drift * 0.3) * 3 + drift * 2) % W;
    const y = (p.y + Math.sin(p.dir + drift * 0.2) * 3) % H;
    const a = 0.025 + 0.05 * (0.5 + 0.5 * Math.sin(time * 0.4 + p.phase));
    ctx.fillStyle = `rgba(210,205,190,${a.toFixed(3)})`;
    ctx.beginPath();
    ctx.arc(x, y, p.r, 0, Math.PI * 2);
    ctx.fill();
  }

  // ── Tejido (Sol) ──
  ctx.save();
  ctx.translate(CX, CY);
  ctx.scale(pulseScale, pulseScale);
  ctx.translate(-CX, -CY);

  const cellHalf = cellSize / 2;
  const inset = 0.8;

  for (const c of cells) {
    const revealHere = smoothstep(c.order - 0.015, c.order + 0.03, reveal);
    if (revealHere <= 0.001) continue;

    // Alpha base — sólido y estable
    let a = c.weight * 0.86 * revealHere;

    if (woven) {
      // ── Capas de vida, todas aditivas y acotadas ──
      let boost = 0;

      // 1. Respiración suave (amplitud ±0.04)
      boost += 0.04 * breathSigned;

      // 2. Shimmer por celda (amplitud ±0.03)
      boost += 0.03 * Math.sin(holdTime * 0.9 + c.seed * 0.0001);

      // 3. Heartbeat radial — intensificado para que se note
      if (heartActive) {
        const distFromWave = Math.abs(c.rPx - heartRadius);
        if (distFromWave < heartWidth) {
          const waveT = 1 - distFromWave / heartWidth;
          boost += 0.45 * waveT * waveT;
        }
      }

      // 4. Escaneo angular 8-fold — intensificado
      const eightFoldDiff = Math.abs(
        ((c.theta - scanAngle + Math.PI * 20) % (Math.PI / 4)) - Math.PI / 8
      );
      const scanBoost = Math.max(0, 1 - eightFoldDiff * 5);
      boost += 0.26 * scanBoost * Math.min(1, c.r / 6);

      // 5. Firings aleatorios — más visibles
      const fireHash = Math.sin(c.seed * 0.0001 + fireSlot * 13.37);
      const fireRand = ((fireHash * 43758.5453) % 1 + 1) % 1;
      if (fireRand < 0.022) {
        const fireShape = Math.max(0, 1 - fireLocal * 1.2);
        boost += 0.62 * fireShape * fireShape;
      }

      a = Math.min(0.98, a + boost);
    }

    if (a <= 0.01) continue;

    ctx.fillStyle = `rgba(236,230,214,${a.toFixed(3)})`;
    ctx.fillRect(c.x - cellHalf + inset, c.y - cellHalf + inset, cellSize - inset * 2, cellSize - inset * 2);
  }

  // ── PULSOS desde las 8 puntas exteriores hacia el centro ──
  // Cada pulso nace en uno de los 8 rombos exteriores (r ≈ 22 celdas) y
  // viaja acelerando hacia el centro. Cuando llega, el corazón del Sol
  // flash-ea. Representa las voces colombianas alimentando a la Madre.
  let arrivalFlash = 0;
  if (woven) {
    const outerRadius = 22 * cellSize; // ≈ 242 px
    const pulseInterval = 0.55;
    const pulseDuration = 1.8;
    // Miramos todos los pulsos que podrían estar en vuelo ahora mismo.
    // Como pulseDuration > pulseInterval, habrá ~3 pulsos simultáneos.
    const currentSlot = Math.floor(holdTime / pulseInterval);
    for (let k = -4; k <= 0; k++) {
      const slot = currentSlot + k;
      if (slot < 0) continue;
      const startTime = slot * pulseInterval;
      const elapsed = holdTime - startTime;
      if (elapsed < 0 || elapsed > pulseDuration) continue;
      const progress = elapsed / pulseDuration;

      // Trayectoria: accelerating ease
      const eased = progress * progress;
      const r = outerRadius * (1 - eased);

      // Ángulo — ciclamos por los 8 ejes
      const angleIdx = ((slot * 3) + 1) % 8; // stride 3 para alternar visualmente
      const angle = (angleIdx / 8) * Math.PI * 2;
      const x = CX + Math.cos(angle) * r;
      const y = CY + Math.sin(angle) * r;

      // Halo del pulso
      const halo = ctx.createRadialGradient(x, y, 0, x, y, 16);
      halo.addColorStop(0, 'rgba(250,240,215,0.55)');
      halo.addColorStop(0.5, 'rgba(230,220,195,0.18)');
      halo.addColorStop(1, 'rgba(230,220,195,0)');
      ctx.fillStyle = halo;
      ctx.beginPath();
      ctx.arc(x, y, 16, 0, Math.PI * 2);
      ctx.fill();

      // Núcleo del pulso
      const coreA = 0.95 * (1 - Math.max(0, progress - 0.95) * 20);
      ctx.fillStyle = `rgba(252,242,218,${coreA.toFixed(3)})`;
      ctx.beginPath();
      ctx.arc(x, y, 2.6, 0, Math.PI * 2);
      ctx.fill();

      // Estela corta
      for (let t = 1; t <= 5; t++) {
        const prevT = progress - t * 0.025;
        if (prevT < 0) break;
        const prevEased = prevT * prevT;
        const prevR = outerRadius * (1 - prevEased);
        const px = CX + Math.cos(angle) * prevR;
        const py = CY + Math.sin(angle) * prevR;
        const tailA = 0.48 - t * 0.08;
        if (tailA <= 0) break;
        ctx.fillStyle = `rgba(232,220,195,${tailA.toFixed(3)})`;
        ctx.beginPath();
        ctx.arc(px, py, 1.5 - t * 0.18, 0, Math.PI * 2);
        ctx.fill();
      }

      // Si está llegando, acumular flash
      if (progress > 0.9) {
        arrivalFlash = Math.max(arrivalFlash, (progress - 0.9) / 0.1);
      }
    }
  }

  // Punto luminoso en el corazón del Sol — boost cuando llega un pulso
  if (reveal > 0.05) {
    const beatBoost = heartActive ? Math.max(0, 1 - heartProgress * 3) : 0;
    const centerA = (0.42 + 0.18 * breath + 0.22 * beatBoost + 0.45 * arrivalFlash) * reveal;
    const g = ctx.createRadialGradient(CX, CY, 0, CX, CY, 38);
    g.addColorStop(0, `rgba(255,248,225,${(centerA * 0.98).toFixed(3)})`);
    g.addColorStop(0.45, `rgba(238,228,205,${(centerA * 0.32).toFixed(3)})`);
    g.addColorStop(1, 'rgba(255,248,225,0)');
    ctx.fillStyle = g;
    ctx.beginPath();
    ctx.arc(CX, CY, 38, 0, Math.PI * 2);
    ctx.fill();
  }

  ctx.restore();

  // Viñeta muy suave — apenas insinúa foco sin tapar la corriente de código
  const vg = ctx.createRadialGradient(CX, CY, 520, CX, CY, 960);
  vg.addColorStop(0, 'rgba(0,0,0,0)');
  vg.addColorStop(1, 'rgba(0,0,0,0.32)');
  ctx.fillStyle = vg;
  ctx.fillRect(0, 0, W, H);

  ctx.restore();
}

// ── Utilidades ──────────────────────────────────────────────────────────────

function smoothstep(a, b, x) {
  const t = Math.max(0, Math.min(1, (x - a) / (b - a)));
  return t * t * (3 - 2 * t);
}

function mulberry32(seed) {
  let a = seed >>> 0;
  return function () {
    a = (a + 0x6D2B79F5) >>> 0;
    let t = a;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

Object.assign(window, { WovenScene });
