// ui_kits/site/Landing.jsx — experimental landing. minimal title + 3 doors.
// Particle field switches PHYSICS per hovered door:
//   about       → constellation: particles pull toward 5 anchor stars + draw connecting lines
//   experiments → grid lock:      particles snap to a flowing dot grid
//   fun         → gravity flip:   particles repel from cursor + drift upward like fireworks
//   idle        → ambient brownian drift

const DOORS = [
  { id: 'about',       label: 'about',       hint: 'who · resume · the longer version',  mood: 'constellation' },
  { id: 'experiments', label: 'experiments', hint: 'prototypes · shaders · half-built',  mood: 'grid'          },
  { id: 'fun',         label: 'fun',         hint: 'games · toys · things to click',     mood: 'fireworks'     },
];

const Landing = ({ setRoute, mode }) => {
  const canvasRef = React.useRef(null);
  const stateRef  = React.useRef({ mouse: { x: -9999, y: -9999 }, mood: 'idle' });
  const [hover, setHover] = React.useState(null);
  const [count, setCount] = React.useState(0);

  React.useEffect(() => { stateRef.current.mood = hover?.mood || 'idle'; }, [hover]);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    const dpr = Math.min(devicePixelRatio || 1, 2);
    let w = 0, h = 0;
    let particles = [];
    let stars = [];     // constellation anchors
    let raf, t0 = performance.now();

    const resize = () => {
      w = canvas.clientWidth; h = canvas.clientHeight;
      canvas.width = w * dpr; canvas.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    const seed = () => {
      const target = Math.min(160, Math.floor((w * h) / 8000));
      particles = Array.from({ length: target }, () => ({
        x: Math.random() * w, y: Math.random() * h,
        vx: (Math.random() - 0.5) * 0.4,
        vy: (Math.random() - 0.5) * 0.4,
        r: 1 + Math.random() * 1.6,
        // each particle has a home position for grid-lock physics
        gx: 0, gy: 0,
      }));
      stars = [];
      for (let i = 0; i < 6; i++) {
        stars.push({ x: w * (0.2 + 0.6 * Math.random()), y: h * (0.2 + 0.6 * Math.random()) });
      }
    };
    resize(); seed();
    const onResize = () => { resize(); seed(); };
    addEventListener('resize', onResize);

    const onMove = (e) => {
      const r = canvas.getBoundingClientRect();
      stateRef.current.mouse.x = e.clientX - r.left;
      stateRef.current.mouse.y = e.clientY - r.top;
    };
    addEventListener('pointermove', onMove);

    const css = (name, fb) => (getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fb);

    const tick = () => {
      const { mouse, mood } = stateRef.current;
      const fg     = css('--fg',     '#fff');
      const accent = css('--accent', '#f60');
      const t = (performance.now() - t0) / 1000;

      ctx.clearRect(0, 0, w, h);

      // ---- per-mood physics ----
      const cols = Math.round(w / 48);
      const rows = Math.round(h / 48);
      const gx0 = (w - cols * 48) / 2 + 24;
      const gy0 = (h - rows * 48) / 2 + 24;

      for (let i = 0; i < particles.length; i++) {
        const p = particles[i];

        if (mood === 'constellation') {
          // pull toward nearest star, slow
          let nearest = stars[0], nd = Infinity;
          for (const s of stars) {
            const d = (s.x - p.x) ** 2 + (s.y - p.y) ** 2;
            if (d < nd) { nd = d; nearest = s; }
          }
          p.vx += (nearest.x - p.x) * 0.0008;
          p.vy += (nearest.y - p.y) * 0.0008;
          p.vx *= 0.93; p.vy *= 0.93;
        } else if (mood === 'grid') {
          // snap to grid cell home
          const ci = i % cols;
          const ri = Math.floor(i / cols) % rows;
          p.gx = gx0 + ci * 48 + Math.sin(t * 1.2 + i * 0.6) * 4;
          p.gy = gy0 + ri * 48 + Math.cos(t * 1.0 + i * 0.4) * 4;
          p.vx += (p.gx - p.x) * 0.08;
          p.vy += (p.gy - p.y) * 0.08;
          p.vx *= 0.78; p.vy *= 0.78;
        } else if (mood === 'fireworks') {
          // strong repulsion from cursor + upward buoyancy
          const dx = p.x - mouse.x, dy = p.y - mouse.y;
          const d2 = dx * dx + dy * dy;
          const R = 220;
          if (d2 < R * R) {
            const d = Math.max(8, Math.sqrt(d2));
            const f = (R - d) / R;
            p.vx += (dx / d) * f * 1.6;
            p.vy += (dy / d) * f * 1.6;
          }
          p.vy -= 0.04;                              // gravity flipped
          p.vx += (Math.random() - 0.5) * 0.4;
          p.vx *= 0.985; p.vy *= 0.985;
        } else {
          // idle: gentle brownian drift, slight cursor repulsion
          p.vx += (Math.random() - 0.5) * 0.08;
          p.vy += (Math.random() - 0.5) * 0.08;
          const dx = p.x - mouse.x, dy = p.y - mouse.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < 140 * 140) {
            const d = Math.max(8, Math.sqrt(d2));
            const f = (140 - d) / 140;
            p.vx += (dx / d) * f * 0.6;
            p.vy += (dy / d) * f * 0.6;
          }
          p.vx *= 0.99; p.vy *= 0.99;
        }

        p.x += p.vx; p.y += p.vy;
        // wrap (fireworks lets things drift off the top intentionally — wrap from below)
        if (p.x < -10) p.x = w + 10; if (p.x > w + 10) p.x = -10;
        if (p.y < -10) p.y = h + 10; if (p.y > h + 10) p.y = -10;
      }

      // ---- per-mood rendering ----
      if (mood === 'constellation') {
        // lines from each particle to its nearest star
        ctx.strokeStyle = `color-mix(in oklch, ${accent} 60%, transparent)`;
        ctx.lineWidth = 0.6;
        for (const p of particles) {
          let nearest = stars[0], nd = Infinity;
          for (const s of stars) {
            const d = (s.x - p.x) ** 2 + (s.y - p.y) ** 2;
            if (d < nd) { nd = d; nearest = s; }
          }
          if (nd < 220 * 220) {
            ctx.globalAlpha = 1 - Math.sqrt(nd) / 220;
            ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(nearest.x, nearest.y); ctx.stroke();
          }
        }
        ctx.globalAlpha = 1;
        // stars themselves
        for (const s of stars) {
          ctx.fillStyle = accent;
          ctx.beginPath(); ctx.arc(s.x, s.y, 3, 0, Math.PI * 2); ctx.fill();
        }
      } else if (mood === 'grid') {
        // faint grid backdrop
        ctx.strokeStyle = `color-mix(in oklch, ${fg} 12%, transparent)`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        for (let i = 0; i <= cols; i++) { ctx.moveTo(gx0 - 24 + i * 48, gy0 - 24); ctx.lineTo(gx0 - 24 + i * 48, gy0 - 24 + rows * 48); }
        for (let j = 0; j <= rows; j++) { ctx.moveTo(gx0 - 24, gy0 - 24 + j * 48); ctx.lineTo(gx0 - 24 + cols * 48, gy0 - 24 + j * 48); }
        ctx.stroke();
      } else {
        // idle: link near particles
        ctx.strokeStyle = `color-mix(in oklch, ${fg} 30%, transparent)`;
        ctx.lineWidth = 0.6;
        const L = 90;
        for (let i = 0; i < particles.length; i++) {
          for (let j = i + 1; j < particles.length; j++) {
            const a = particles[i], b = particles[j];
            const dx = a.x - b.x, dy = a.y - b.y;
            const d2 = dx * dx + dy * dy;
            if (d2 < L * L) {
              ctx.globalAlpha = (1 - Math.sqrt(d2) / L) * 0.5;
              ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y); ctx.stroke();
            }
          }
        }
        ctx.globalAlpha = 1;
      }

      // particles
      for (const p of particles) {
        ctx.fillStyle = (mood === 'fireworks' || mood === 'constellation') ? accent : fg;
        ctx.globalAlpha = (mood === 'fireworks' || mood === 'constellation') ? 0.9 : 0.55;
        const r = mood === 'fireworks' ? p.r * 1.4 : p.r;
        ctx.beginPath(); ctx.arc(p.x, p.y, r, 0, Math.PI * 2); ctx.fill();
      }
      ctx.globalAlpha = 1;

      raf = requestAnimationFrame(tick);
    };
    tick();

    return () => {
      cancelAnimationFrame(raf);
      removeEventListener('pointermove', onMove);
      removeEventListener('resize', onResize);
    };
  }, [mode]);

  const openDoor = (id) => { setCount(c => c + 1); setRoute('/' + id); };

  return (
    <section className="koa-landing" data-cursor="hot">
      <canvas ref={canvasRef} className="field" aria-hidden="true" />

      <span className="badge-tl">→ koa.codes</span>
      <span className="badge-tr">{String(count).padStart(3, '0')} / interactions</span>

      <div className="stage">
        <h1 className="word site-tagline">
          koa<span className="dot" />codes
        </h1>

        <ul className="doors">
          {DOORS.map((d, i) => (
            <li key={d.id} className="door" data-hot
              onMouseEnter={() => setHover(d)}
              onMouseLeave={() => setHover(curr => curr?.id === d.id ? null : curr)}
              onClick={() => openDoor(d.id)}>
              <span className="door-num">0{i + 1}</span>
              <span className="door-label">{d.label}<span className="door-end">.</span></span>
              <span className="door-hint">{d.hint}</span>
              <span className="door-arrow">→</span>
            </li>
          ))}
        </ul>

        <p className="status">
          <span>→ {hover ? `mood: ${hover.mood}` : 'mood: idle · move your cursor'}</span>
          <span>·</span>
          <span>→ press <kbd>:</kbd> for the command palette</span>
        </p>
      </div>

      <style>{`
        .koa-landing {
          position: relative; min-height: 100vh; padding: 0;
          display: grid; place-items: center; overflow: hidden; isolation: isolate;
        }
        .field {
          position: absolute; inset: 0; width: 100%; height: 100%;
          z-index: 0; pointer-events: none;
        }
        .stage {
          position: relative; z-index: 1;
          display: flex; flex-direction: column; align-items: center; gap: var(--s-5);
          padding: 0 var(--s-4);
        }

        .badge-tl, .badge-tr {
          position: absolute; top: 22px; z-index: 2;
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em;
          text-transform: uppercase; color: var(--fg-muted);
          mix-blend-mode: difference;
        }
        .badge-tl { left: 24px; }
        .badge-tr { right: 24px; font-variant-numeric: tabular-nums; }

        .word {
          font-family: var(--font-display); font-weight: 800;
          font-variation-settings: "opsz" 96, "wdth" 80;
          font-size: clamp(56px, 10vw, 156px); line-height: 0.92; letter-spacing: -0.055em;
          margin: 0; color: var(--fg);
          mix-blend-mode: difference;
          display: inline-flex; align-items: baseline; gap: 0;
        }
        .word .dot {
          display: inline-block; width: 0.14em; height: 0.14em;
          background: var(--accent); border-radius: 50%;
          margin: 0 0.02em; transform: translateY(-0.05em);
          box-shadow: 0 0 40px color-mix(in oklch, var(--accent) 70%, transparent);
        }

        .doors {
          list-style: none; padding: 6px; margin: 0;
          display: flex; gap: 0; flex-wrap: wrap; justify-content: center;
          background: color-mix(in oklch, var(--bg) 55%, transparent);
          backdrop-filter: blur(20px) saturate(180%);
          -webkit-backdrop-filter: blur(20px) saturate(180%);
          border: 1px solid var(--border);
          border-radius: 9999px;
        }
        .door {
          display: grid;
          grid-template-columns: auto auto 1fr auto;
          align-items: baseline; gap: 8px;
          padding: 10px 18px;
          border-radius: 9999px;
          cursor: pointer;
          transition: background 220ms var(--ease-out), color 220ms var(--ease-out);
          font-family: var(--font-sans); color: var(--fg);
        }
        .door:hover { background: var(--fg); color: var(--bg); }
        .door-num   { font-family: var(--font-mono); font-size: 10px; opacity: 0.55; letter-spacing: 0.06em; }
        .door-label { font-family: var(--font-display); font-weight: 700; font-variation-settings: "opsz" 32, "wdth" 90; font-size: 18px; letter-spacing: -0.02em; line-height: 1; }
        .door-label .door-end { color: var(--accent); }
        .door:hover .door-label .door-end { color: var(--bg); }
        .door-hint  { font-family: var(--font-mono); font-size: 11px; opacity: 0; transform: translateX(-4px); transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out); letter-spacing: 0.02em; }
        .door:hover .door-hint { opacity: 0.7; transform: translateX(0); }
        .door-arrow { font-family: var(--font-sans); font-size: 16px; opacity: 0.4; transition: transform 240ms var(--ease-warrior), opacity 220ms var(--ease-out); }
        .door:hover .door-arrow { transform: translateX(4px); opacity: 1; }

        .status {
          font-family: var(--font-mono); font-size: 11px; color: var(--fg-faint);
          letter-spacing: 0.04em; text-transform: uppercase; margin: 0;
          display: flex; gap: 12px; align-items: center; flex-wrap: wrap; justify-content: center;
        }
        .status kbd {
          font-family: var(--font-mono); padding: 1px 6px; border: 1px solid var(--border-strong);
          border-radius: 4px; font-size: 10px; color: var(--fg);
        }

        @media (max-width: 640px) {
          .doors { flex-direction: column; border-radius: 22px; align-items: stretch; gap: 4px; }
          .door  { border-radius: 18px; padding: 12px 16px; }
          .door-hint { display: none; }
          .badge-tl, .badge-tr { top: 16px; }
        }
      `}</style>
    </section>
  );
};

window.Landing = Landing;
