/* Harbour hero — five 3D-extruded agent SVGs orbit a central Harbour hub,
   wired in by glowing connection lines. Behind everything: the 2D anchor
   mark spinning slowly on its Y axis as a moody backdrop. */

const AGENTS = [
  { id: "claude-code", label: "Claude Code", src: "assets/icons/claude-code.svg" },
  { id: "codex", label: "Codex", src: "assets/icons/codex.svg" },
  { id: "cursor", label: "Cursor", src: "assets/icons/cursor.svg" },
  { id: "gemini", label: "Gemini", src: "assets/icons/gemini.svg" },
  { id: "opencode", label: "OpenCode", src: "assets/icons/opencode.svg" },
];

const POS_FRACTIONS = [
  { x: 0.04, y: 0.18 },
  { x: 0.2, y: 0.74 },
  { x: 0.92, y: 0.18 },
  { x: 0.76, y: 0.74 },
  { x: 0.48, y: 0.04 },
];

function Nav() {
  return (
    <nav className="topnav" data-screen-label="nav">
      <div className="topnav-inner">
        <a href="https://harbour-systems.com/" className="topnav-brand" aria-label="Harbour home">
          <img src="assets/harbour-wordmark.png" alt="Harbour" id="harbour-brand-img" />
          <span className="topnav-badge">v0.1 alpha</span>
        </a>
        <div className="topnav-links" aria-label="primary">
          <a href="#how">How it works</a>
          <a href="#timeline">Timeline</a>
          <a href="#downloads">Download</a>
        </div>
        <a className="topnav-cta" data-harbour-auth-link href="sign-in.html">
          Sign in
        </a>
      </div>
    </nav>
  );
}

/* Tiny dedicated Three.js mount that hands itself to window.initHarbourLogo3D
   so each orbiter renders a single 3D-extruded SVG of its agent's logo. */
function Logo3D({ agentId }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const host = ref.current;
    if (!host) return;
    let dispose = () => {};
    let cancelled = false;
    const start = () => {
      if (cancelled || !window.initHarbourLogo3D) return;
      const result = window.initHarbourLogo3D(host, agentId);
      Promise.resolve(result).then((d) => {
        if (cancelled) {
          if (typeof d === "function") d();
          return;
        }
        if (typeof d === "function") dispose = d;
      });
    };
    if (window.initHarbourLogo3D) start();
    else window.addEventListener("harbour-3d-ready", start, { once: true });
    return () => {
      cancelled = true;
      dispose();
      window.removeEventListener("harbour-3d-ready", start);
    };
  }, [agentId]);
  return <div className="orbiter-3d" ref={ref} aria-hidden="true" />;
}

function Hero() {
  const heroRef = React.useRef(null);
  const stageRef = React.useRef(null);
  const hubRef = React.useRef(null);

  const [geom, setGeom] = React.useState({
    w: 600,
    h: 600,
    stageL: 0,
    stageT: 0,
    topPortX: 300,
    topPortY: 580,
    botPortX: 300,
    botPortY: 620,
  });

  React.useLayoutEffect(() => {
    const hero = heroRef.current;
    const stage = stageRef.current;
    const hub = hubRef.current;
    if (!hero || !stage || !hub) return;
    const measure = () => {
      const hRect = hero.getBoundingClientRect();
      const sRect = stage.getBoundingClientRect();
      const huRect = hub.getBoundingClientRect();
      const cx = huRect.left - hRect.left + huRect.width / 2;
      const cy = huRect.top - hRect.top + huRect.height / 2;
      const portDX = 28;
      const portDY = 24;
      setGeom({
        w: hRect.width,
        h: hRect.height,
        stageL: sRect.left - hRect.left,
        stageT: sRect.top - hRect.top,
        stageW: sRect.width,
        stageH: sRect.height,
        topPortX: cx + portDX,
        topPortY: cy - portDY,
        botPortX: cx + portDX,
        botPortY: cy + portDY,
      });
    };
    measure();
    const ro1 = new ResizeObserver(measure);
    ro1.observe(hero);
    const ro2 = new ResizeObserver(measure);
    ro2.observe(stage);
    const ro3 = new ResizeObserver(measure);
    ro3.observe(hub);
    window.addEventListener("scroll", measure, { passive: true });
    window.addEventListener("resize", measure);
    return () => {
      ro1.disconnect();
      ro2.disconnect();
      ro3.disconnect();
      window.removeEventListener("scroll", measure);
      window.removeEventListener("resize", measure);
    };
  }, []);

  const points = AGENTS.map((a, i) => {
    const f = POS_FRACTIONS[i];
    const ox = geom.stageL + (geom.stageW || 0) * f.x + 26;
    const oy = geom.stageT + (geom.stageH || 0) * f.y + 26;
    return { id: a.id, ox, oy };
  });

  const hubCX = (geom.topPortX + geom.botPortX) / 2 - 28;
  const hubCY = (geom.topPortY + geom.botPortY) / 2;
  const dockRadius = 22;
  const paths = points.map((p) => {
    const dx = hubCX - p.ox;
    const dy = hubCY - p.oy;
    const len = Math.hypot(dx, dy) || 1;
    const ex = hubCX - (dx / len) * dockRadius;
    const ey = hubCY - (dy / len) * dockRadius;
    const d = `M ${p.ox} ${p.oy} L ${ex} ${ey}`;
    return { id: p.id, d, port: { x: ex, y: ey } };
  });

  return (
    <section className="hero" data-screen-label="hero" ref={heroRef}>
      {/* Anchor backdrop — three masked layers (body / rim / gloss) styled in
          CSS so it reads as a polished metal anchor, then spun together on
          its Y axis. */}
      <div className="hero-anchor-bg" aria-hidden="true">
        <div className="hero-anchor-bg-inner">
          <div className="anchor-3d-inner" />
          <div className="anchor-3d-rim" />
          <div className="anchor-3d-gloss" />
        </div>
      </div>

      <svg
        className="hero-wires"
        viewBox={`0 0 ${geom.w} ${geom.h}`}
        preserveAspectRatio="none"
        aria-hidden="true"
      >
        <defs>
          <linearGradient id="wireGrad" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0" stopColor="rgba(160, 210, 255, 0)" />
            <stop offset="0.5" stopColor="rgba(200, 225, 255, 0.75)" />
            <stop offset="1" stopColor="rgba(170, 160, 250, 0.2)" />
          </linearGradient>
          <filter id="wireGlowFilter" x="-20%" y="-20%" width="140%" height="140%">
            <feGaussianBlur stdDeviation="1.6" result="b" />
            <feMerge>
              <feMergeNode in="b" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>
        {paths.map((p, i) => (
          <g key={p.id}>
            <path d={p.d} className="wire-base" />
            <path
              d={p.d}
              className="wire-glow"
              stroke="url(#wireGrad)"
              filter="url(#wireGlowFilter)"
              style={{ animation: `wireDash 3.4s ${(i * 0.25) % 1.5}s ease-in-out infinite` }}
            />
          </g>
        ))}
      </svg>

      <div className="wrap hero-stack">
        <div className="hero-copy">
          <h1 className="display hero-title">
            The memory <em>orchestration</em> layer
            <br />
            for your AI agents.
          </h1>
          <p className="lede">
            One addressable context store. Every agent reads and writes the same receipts.
          </p>
          <div className="hero-actions">
            <a href="#downloads" className="btn btn-primary">
              Download Harbour
              <span aria-hidden="true">↓</span>
            </a>
            <a href="#how" className="btn btn-ghost">
              See how it works
              <span className="kbd">↵</span>
            </a>
          </div>
        </div>

        <div className="stage" ref={stageRef}>
          <div className="hub" ref={hubRef}>
            <span className="hub-halo" aria-hidden="true" />
            <span className="hub-ring" aria-hidden="true" />
            <div role="img" aria-label="Harbour" className="hub-mark" />
          </div>

          {AGENTS.map((a, i) => {
            const f = POS_FRACTIONS[i];
            return (
              <div
                className="orbiter"
                key={a.id}
                title={a.label}
                style={{ left: `${f.x * 100}%`, top: `${f.y * 100}%` }}
              >
                <Logo3D agentId={a.id} />
                <span className="orbiter-label">{a.label}</span>
              </div>
            );
          })}
        </div>
      </div>

      <style>{`
        @keyframes wireDash {
          0%   { stroke-dasharray: 6 220; stroke-dashoffset:    0; opacity: 0.95; }
          50%  { opacity: 0.55; }
          100% { stroke-dasharray: 6 220; stroke-dashoffset: -226; opacity: 0.95; }
        }
        .hero-wires .wire-glow { stroke-dasharray: 6 220; }
      `}</style>
    </section>
  );
}

function Tagline() {
  return (
    <section className="tagline-block" data-screen-label="tagline">
      <div className="tagline-inner">
        <div className="tagline-sup">§ The layer</div>
        <h2 className="tagline">
          One address for <em>every</em> context.
        </h2>
        <p className="tagline-sub">The next agent picks up exactly where the last one left off.</p>
      </div>
    </section>
  );
}

Object.assign(window, { Nav, Hero, Tagline });
