/* ============ shared hooks/helpers ============ */
const { useState, useEffect, useLayoutEffect, useRef, useCallback } = React;

function useInView(opts) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setSeen(true); io.disconnect(); }
    }, { threshold: 0.18, ...(opts || {}) });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return [ref, seen];
}

function Reveal({ children, d = 0, cls = "", tag = "div" }) {
  const [ref, seen] = useInView();
  const Tag = tag;
  return <Tag ref={ref} className={`reveal ${d ? "d" + d : ""} ${seen ? "in" : ""} ${cls}`}>{children}</Tag>;
}

/* clip line-by-line heading */
function Lines({ items, className = "" }) {
  const [ref, seen] = useInView();
  return (
    <div ref={ref} className={`lines ${seen ? "in" : ""} ${className}`}>
      {items.map((t, i) => <span key={i}><i>{t}</i></span>)}
    </div>
  );
}

/* ============ HERO interactive node field ============ */
function HeroCanvas() {
  const canvasRef = useRef(null);
  const wrapRef = useRef(null);
  useEffect(() => {
    const cv = canvasRef.current, wrap = wrapRef.current;
    const ctx = cv.getContext("2d");
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    let W = 0, H = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
    let raf, t = 0;
    const mouse = { x: 0.5, y: 0.5, tx: 0.5, ty: 0.5 };

    // normalized node layout: a HW x SW system
    const nodes = [
      { x: .12, y: .30, label: "地域 / 人", en: "PEOPLE", k: "sw" },
      { x: .30, y: .68, label: "アプリ", en: "APP", k: "sw" },
      { x: .50, y: .24, label: "センサー", en: "SENSOR", k: "hw" },
      { x: .70, y: .60, label: "AI", en: "AI", k: "sw" },
      { x: .50, y: .82, label: "ロボット", en: "ROBOT", k: "hw" },
      { x: .86, y: .32, label: "クラウド", en: "CLOUD", k: "sw" },
      { x: .40, y: .46, label: "デバイス", en: "DEVICE", k: "hw" },
    ];
    const edges = [[0,1],[1,6],[6,2],[2,3],[3,5],[6,3],[1,4],[4,3],[0,6],[2,5]];
    nodes.forEach(n => { n.ph = Math.random() * 6.28; n.ax = .012 + Math.random()*.01; n.ay = .012 + Math.random()*.01; });
    // bits traveling along edges
    const bits = edges.map((e, i) => ({ e, p: Math.random(), sp: .0012 + Math.random()*.0016 }));

    function resize() {
      W = wrap.clientWidth; H = wrap.clientHeight;
      cv.width = W * dpr; cv.height = H * dpr;
      cv.style.width = W + "px"; cv.style.height = H + "px";
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    resize();
    const ro = new ResizeObserver(resize); ro.observe(wrap);

    function pos(n) {
      const px = mouse.x - .5, py = mouse.y - .5;
      const fx = n.x + Math.sin(t * n.ax + n.ph) * .012 + px * (.04 + (n.k==="hw"?.02:0));
      const fy = n.y + Math.cos(t * n.ay + n.ph) * .012 + py * (.04 + (n.k==="hw"?.02:0));
      return { x: fx * W, y: fy * H };
    }

    const css = getComputedStyle(document.documentElement);
    const accent = css.getPropertyValue("--accent").trim() || "#7ae800";
    const ink = "#0c0c0b", grey = "#b9b6af", line = "#d2cfc8";

    function draw() {
      t += reduce ? 0 : 1;
      mouse.x += (mouse.tx - mouse.x) * .06;
      mouse.y += (mouse.ty - mouse.y) * .06;
      ctx.clearRect(0, 0, W, H);
      const P = nodes.map(pos);

      // edges
      edges.forEach((e) => {
        const a = P[e[0]], b = P[e[1]];
        ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y);
        ctx.strokeStyle = line; ctx.lineWidth = 1; ctx.stroke();
      });
      // traveling bits
      bits.forEach(bt => {
        if (!reduce) bt.p += bt.sp; if (bt.p > 1) bt.p -= 1;
        const a = P[bt.e[0]], b = P[bt.e[1]];
        const x = a.x + (b.x - a.x) * bt.p, y = a.y + (b.y - a.y) * bt.p;
        ctx.beginPath(); ctx.rect(x - 2, y - 2, 4, 4);
        ctx.fillStyle = accent; ctx.fill();
      });
      // nodes
      P.forEach((p, i) => {
        const n = nodes[i];
        const hw = n.k === "hw";
        // hit-glow near mouse
        const mx = mouse.x * W, my = mouse.y * H;
        const dist = Math.hypot(mx - p.x, my - p.y);
        const near = Math.max(0, 1 - dist / 180);
        if (hw) {
          ctx.beginPath(); ctx.rect(p.x - 5, p.y - 5, 10, 10);
          ctx.fillStyle = "#fff"; ctx.fill();
          ctx.lineWidth = near > .1 ? 2 : 1.4; ctx.strokeStyle = near > .1 ? accent : ink; ctx.stroke();
        } else {
          ctx.beginPath(); ctx.arc(p.x, p.y, 5.5, 0, 6.2832);
          ctx.fillStyle = ink; ctx.fill();
          if (near > .1) { ctx.beginPath(); ctx.arc(p.x, p.y, 9, 0, 6.2832); ctx.strokeStyle = accent; ctx.lineWidth = 1.5; ctx.stroke(); }
        }
        // label
        ctx.font = "600 11px 'Roboto Mono', monospace";
        ctx.fillStyle = near > .1 ? ink : grey;
        ctx.fillText(n.en, p.x + 12, p.y + 4);
        ctx.font = "700 12px 'Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif";
        ctx.fillStyle = near > .1 ? ink : "#8d8a83";
        ctx.fillText(n.label, p.x + 12, p.y - 9);
      });
      raf = requestAnimationFrame(draw);
    }
    draw();

    function onMove(e) {
      const r = wrap.getBoundingClientRect();
      mouse.tx = (e.clientX - r.left) / r.width;
      mouse.ty = (e.clientY - r.top) / r.height;
    }
    wrap.addEventListener("pointermove", onMove);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); wrap.removeEventListener("pointermove", onMove); };
  }, []);
  return <div className="hero-canvas-wrap" ref={wrapRef}><canvas ref={canvasRef} /></div>;
}

/* ============ HERO ============ */
function Hero({ go }) {
  return (
    <header className="hero section" id="home">
      <HeroCanvas />
      <div className="hero-grid-overlay" aria-hidden="true"></div>
      <div className="wrap hero-inner">
        <div className="hero-meta mono">
          <span>HASHBIT Inc.</span>
          <span className="hero-status"><i></i>SYSTEM ONLINE</span>
        </div>
        <h1 className="hero-title">
          <Lines items={["ハードウェア × ソフトウェアで、", "誰かのインフラになる。"]} />
        </h1>
        <Reveal d2><p className="hero-sub mono">Building infrastructure for people<br/>through hardware and software.</p></Reveal>
        <Reveal d3>
          <div className="hero-cta">
            <button className="btn accent" onClick={() => go("works")}>View Our Works <span className="arr">→</span></button>
            <button className="btn ghost" onClick={() => go("contact")}>Contact Us <span className="arr">→</span></button>
          </div>
        </Reveal>
      </div>
      <div className="hero-foot wrap mono">
        <span>01 — 接続されたひとつのシステム</span>
        <span className="scrollcue">SCROLL <i></i></span>
      </div>
    </header>
  );
}

Object.assign(window, { useInView, Reveal, Lines, Hero });
