// Hero with curved gradient hill + particle field
// Renders to a <canvas> for smooth animation.

const { useEffect, useRef } = React;

function HeroCanvas() {
  const canvasRef = useRef(null);
  const rafRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);

    const resize = () => {
      const rect = canvas.parentElement.getBoundingClientRect();
      w = rect.width; h = rect.height;
      canvas.width = w * dpr; canvas.height = h * dpr;
      canvas.style.width = w + 'px'; canvas.style.height = h + 'px';
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      seedParticles();
    };

    // Curved hill path: starts lower-left, rises to upper-right.
    // Sketch-accurate: a smooth bezier arch.
    const hillPath = () => {
      const p = new Path2D();
      const leftX = -40;
      const leftY = h + 20;
      const rightX = w + 40;
      const rightY = h * 0.12;
      const cp1x = w * 0.35, cp1y = h * 1.05;
      const cp2x = w * 0.55, cp2y = h * 0.05;
      p.moveTo(leftX, leftY);
      p.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, rightX, rightY);
      p.lineTo(rightX, h + 20);
      p.lineTo(leftX, h + 20);
      p.closePath();
      return { path: p, cp1x, cp1y, cp2x, cp2y, leftX, leftY, rightX, rightY };
    };

    // Hill outline curves (the ridges in the sketch)
    const drawRidges = (hill) => {
      const { leftX, leftY, cp1x, cp1y, cp2x, cp2y, rightX, rightY } = hill;
      for (let i = 0; i < 5; i++) {
        ctx.beginPath();
        const off = i * 8;
        ctx.moveTo(leftX, leftY - off * 0.4);
        ctx.bezierCurveTo(cp1x, cp1y - off, cp2x, cp2y - off, rightX, rightY - off);
        const t = i / 4;
        const rr = Math.round(124 + (6 - 124) * t);
        const gg = Math.round(58 + (182 - 58) * t);
        const bb = Math.round(237 + (212 - 237) * t);
        ctx.strokeStyle = `rgba(${rr}, ${gg}, ${bb}, ${0.28 - i * 0.045})`;
        ctx.lineWidth = 1;
        ctx.stroke();
      }
    };

    // Particles inside hill
    let particles = [];
    const PARTICLE_COUNT = 140;
    const seedParticles = () => {
      particles = [];
      for (let i = 0; i < PARTICLE_COUNT; i++) {
        particles.push({
          x: Math.random() * w,
          y: Math.random() * h,
          vx: (Math.random() - 0.5) * 0.2,
          vy: -0.1 - Math.random() * 0.25,
          r: Math.random() * 1.4 + 0.3,
          a: Math.random() * 0.8 + 0.2,
          tw: Math.random() * Math.PI * 2,
        });
      }
    };

    // Check if point is above hill ridge (inside hill region)
    const isInsideHill = (x, y) => {
      // evaluate bezier y at given t ~ x/w; cheap approx via sampling
      const t = Math.max(0, Math.min(1, x / w));
      const oneT = 1 - t;
      // cubic bezier y from leftY → cp1y → cp2y → rightY
      const by =
        oneT * oneT * oneT * (h + 20) +
        3 * oneT * oneT * t * (h * 1.05) +
        3 * oneT * t * t * (h * 0.05) +
        t * t * t * (h * 0.12);
      return y > by;
    };

    let t = 0;
    const render = () => {
      t += 1;
      ctx.clearRect(0, 0, w, h);

      const hill = hillPath();

      // Save + clip to hill
      ctx.save();
      ctx.clip(hill.path);

      // Gradient fill inside hill
      // Brand gradient: purple at top → cyan toward base
      const grad = ctx.createLinearGradient(w * 0.2, h * 0.1, w * 0.85, h);
      grad.addColorStop(0, 'rgba(124, 58, 237, 0.26)');
      grad.addColorStop(0.55, 'rgba(91, 33, 182, 0.18)');
      grad.addColorStop(1, 'rgba(6, 182, 212, 0.0)');
      ctx.fillStyle = grad;
      ctx.fillRect(0, 0, w, h);

      // Cyan highlight glow near upper-right ridge
      const rg = ctx.createRadialGradient(w * 0.72, h * 0.22, 0, w * 0.72, h * 0.22, w * 0.55);
      rg.addColorStop(0, 'rgba(6, 182, 212, 0.22)');
      rg.addColorStop(1, 'rgba(6, 182, 212, 0)');
      ctx.fillStyle = rg;
      ctx.fillRect(0, 0, w, h);

      // Particles
      for (const p of particles) {
        p.x += p.vx;
        p.y += p.vy;
        p.tw += 0.04;
        if (p.y < 0 || p.x < -10 || p.x > w + 10) {
          // respawn near bottom of hill
          p.x = Math.random() * w;
          p.y = h + Math.random() * 20;
          p.vy = -0.1 - Math.random() * 0.25;
        }
        if (!isInsideHill(p.x, p.y)) continue;
        const alpha = p.a * (0.6 + 0.4 * Math.sin(p.tw));
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(220, 250, 255, ${alpha})`;
        ctx.fill();
      }

      ctx.restore();

      // Ridges drawn on top
      drawRidges(hill);
    };

    resize();
    window.addEventListener('resize', resize);

    // Pause the rAF loop when the hero is off-screen or the tab is hidden.
    // This is the main fix for scroll-jank when returning to the top:
    // a 140-particle canvas no longer redraws while the user is reading
    // sections far below it.
    let visible = true;
    const start = () => {
      if (rafRef.current) return;
      const tick = () => { render(); rafRef.current = requestAnimationFrame(tick); };
      rafRef.current = requestAnimationFrame(tick);
    };
    const stop = () => {
      if (rafRef.current) {
        cancelAnimationFrame(rafRef.current);
        rafRef.current = null;
      }
    };
    const update = () => {
      if (visible && !document.hidden) start(); else stop();
    };

    const vio = new IntersectionObserver((entries) => {
      visible = entries[0].isIntersecting;
      update();
    }, { threshold: 0 });
    vio.observe(canvas);

    const onVis = () => update();
    document.addEventListener('visibilitychange', onVis);

    update();

    return () => {
      stop();
      window.removeEventListener('resize', resize);
      document.removeEventListener('visibilitychange', onVis);
      vio.disconnect();
    };
  }, []);

  return <canvas ref={canvasRef} className="hero-canvas" />;
}

function Hero() {
  return (
    <section className="hero" id="top">
      <HeroCanvas />
      <div className="hero-mark-top reveal">
        <LabrynthMark size={64} className="hero-mark-top-img" alt="Labrynth" gradient />
      </div>
      <div className="hero-inner wrap">
        <div className="hero-eyebrow reveal" style={{ transitionDelay: '60ms' }}>
          <span>A way through, by design</span>
        </div>
        <h1 className="reveal" style={{ transitionDelay: '80ms' }}>
          Your website,<br/>already <em>built</em>.
        </h1>
        <p className="hero-sub reveal" style={{ transitionDelay: '160ms' }}>
          I design conversion-focused sites for local businesses, and I'll show you
          yours before you pay a cent.
        </p>
        <div className="hero-ctas reveal" style={{ transitionDelay: '240ms' }}>
          <a href="#contact" className="btn btn-primary" data-hover onClick={window.scrollToHash}>
            See your custom preview
            <span className="arr">→</span>
          </a>
          <a href="#work" className="btn btn-ghost" data-hover onClick={window.scrollToHash}>
            View work
          </a>
        </div>
      </div>

      <div className="hero-bottom">
        <div className="scroll-ind">
          <div className="bar"></div>
          <span className="mono">Scroll</span>
        </div>
        <div className="hero-meta">
          <div><span className="dot">●</span> &nbsp;Labrynth · Independent Studio</div>
          <div>Est. 2026 · Ventura County, Southern California</div>
        </div>
      </div>
    </section>
  );
}

function Marquee() {
  const items = [
    'Tideline', 'Labrynth Automation', 'Lumen & Co.',
    'The Mass Files', 'Ridgeline'
  ];
  const doubled = [...items, ...items];
  return (
    <div className="marquee">
      <div className="marquee-track">
        {doubled.map((x, i) => (
          <span key={i}>
            {x}
            <span className="sep">✦</span>
          </span>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { Hero, Marquee });
