"use client";

import { useEffect, useState, type ComponentType } from "react";
import { motion } from "motion/react";
import { GlobeFallback } from "./GlobeFallback";

/**
 * Thin client boundary around the 3D scene.
 *
 * The import is a bare `await import()` inside an effect rather than
 * `next/dynamic`. That distinction matters: `next/dynamic` registers the module
 * in the loadable manifest, and Next then emits a preload link for its chunk in
 * the document head. The component would not execute until we asked for it, but
 * three.js and drei, about 370 kB of it, would still be downloading while the
 * browser was trying to paint the headline. Importing by hand keeps the chunk
 * off the critical path entirely.
 *
 * The SVG globe carries the composition until the real scene is ready, so the
 * hero never looks unfinished while it waits.
 */

function hasWebGL(): boolean {
  try {
    const canvas = document.createElement("canvas");
    return Boolean(
      window.WebGLRenderingContext &&
        (canvas.getContext("webgl2") || canvas.getContext("webgl")),
    );
  } catch {
    return false;
  }
}

export function GlobeCanvasClient() {
  const [Globe, setGlobe] = useState<ComponentType | null>(null);
  const [settled, setSettled] = useState(false);

  useEffect(() => {
    let cancelled = false;

    const start = () => {
      if (!hasWebGL()) {
        if (!cancelled) setSettled(true);
        return;
      }

      import("./ThreadGlobe")
        .then((mod) => {
          if (cancelled) return;
          setGlobe(() => mod.default);
          setSettled(true);
        })
        .catch(() => {
          // A failed chunk leaves the SVG globe in place, which is a complete
          // picture on its own. Nothing to recover.
          if (!cancelled) setSettled(true);
        });
    };

    // Wait for the browser to finish the work that the reader is waiting on.
    // Safari only shipped requestIdleCallback recently, so fall back to a timer.
    const idle = window.requestIdleCallback;

    if (typeof idle === "function") {
      const handle = idle(start, { timeout: 2000 });
      return () => {
        cancelled = true;
        window.cancelIdleCallback(handle);
      };
    }

    const handle = window.setTimeout(start, 500);
    return () => {
      cancelled = true;
      window.clearTimeout(handle);
    };
  }, []);

  return (
    <div className="absolute inset-0">
      {/* The SVG globe is the poster frame. It holds the composition while the
          scene loads and stays put if WebGL is unavailable. */}
      <motion.div
        className="absolute inset-0 flex items-center justify-center"
        initial={{ opacity: 0, scale: 0.94 }}
        animate={{ opacity: Globe ? 0 : 1, scale: 1 }}
        transition={{ duration: 1.2, ease: [0.16, 1, 0.3, 1] }}
      >
        <GlobeFallback className="h-full max-h-[min(88vh,860px)] w-auto max-w-full" />
      </motion.div>

      {Globe && settled ? (
        <motion.div
          className="absolute inset-0"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ duration: 1.4, delay: 0.15, ease: [0.16, 1, 0.3, 1] }}
        >
          <Globe />
        </motion.div>
      ) : null}
    </div>
  );
}
