// ===== 3D-Nachtglobus: WebGL-Ansicht der Weltkarte (globe.gl) =====
// Teilt Filter-State, Hover/Pin und Stats-Panel mit der 2D-Karte (worldmap.jsx).
// globe.gl wird lazy geladen — erst beim ersten Umschalten auf "Globus".

const { useState: _gbS, useEffect: _gbE, useRef: _gbR, useMemo: _gbM } = React;

const GLOBE_LIB_URL = "https://unpkg.com/globe.gl@2.34.4/dist/globe.gl.min.js";
const GLOBE_TX = "https://unpkg.com/three-globe@2.34.4/example/img/";

let _globeLibPromise = null;
function ensureGlobeLib() {
  if (window.Globe) return Promise.resolve();
  if (!_globeLibPromise) {
    _globeLibPromise = new Promise((resolve, reject) => {
      const s = document.createElement("script");
      s.src = GLOBE_LIB_URL;
      s.onload = resolve;
      s.onerror = () => { _globeLibPromise = null; reject(new Error("globe.gl load failed")); };
      document.head.appendChild(s);
    });
  }
  return _globeLibPromise;
}

let _webglCache = null;
function globeSupported() {
  if (_webglCache !== null) return _webglCache;
  try {
    const c = document.createElement("canvas");
    _webglCache = !!(window.WebGLRenderingContext && (c.getContext("webgl2") || c.getContext("webgl")));
  } catch (e) {
    _webglCache = false;
  }
  return _webglCache;
}

// ----- Karriere-Stationen (Milestone-Kino) -----
// code = Zielflughafen der zugehörigen Route (Pin im Stats-Panel), null = nur Kameraflug.
const GLOBE_MILESTONES = [
  { jahr: 2001, code: "MIA", kurz: "2001 · Miami", titel: "Ausbildungsumlauf Miami",
    text: "Erster USA-Trip überhaupt — LH0462 FRA → MIA auf der Boeing 747, Position AK.",
    pov: { lat: 36, lng: -50, alt: 1.8 } },
  { jahr: 2001, code: "SFO", kurz: "2001 · SFO", titel: "Erster Linienflug",
    text: "1. Juli 2001: LH0458 München → San Francisco, 9.437 km auf der B747-400.",
    pov: { lat: 46, lng: -70, alt: 1.8 } },
  { jahr: 2002, code: "ORD", kurz: "2002 · A340", titel: "Wechsel auf A340",
    text: "Langstrecke. Die Welt wird ein Liniennetz.",
    pov: { lat: 50, lng: -38, alt: 2.0 } },
  { jahr: 2005, code: "TYO", kurz: "2005 · Asien", titel: "Das Asien-Jahr",
    text: "Peking · Shanghai · Tokio · Bangkok — 2026 aus Spesenabrechnungen rekonstruiert.",
    pov: { lat: 40, lng: 100, alt: 1.9 } },
  { jahr: 2007, code: "HKG", kurz: "2007 · F/CL", titel: "F/CL-Flugbegleiter",
    text: "Aufbauschulung am LFTC-MUC — Front-Cabin-Service der A340/A346.",
    pov: { lat: 32, lng: 95, alt: 2.0 } },
  { jahr: 2008, code: null, kurz: "2008 · Purser", titel: "Beförderung zum Purser",
    text: "1. September 2008 — zwei Streifen, Verantwortung für die Kabine. Heimatbasis: München.",
    pov: { lat: 48.35, lng: 11.79, alt: 1.5 } },
  { jahr: 2011, code: "SIN", kurz: "2011 · SIN", titel: "Der letzte Logbuch-Flug",
    text: "14. Dezember 2011: LH0791 Singapur → München, 10.058 km.",
    pov: { lat: 28, lng: 75, alt: 1.9 } },
];

// Replay öffnet alle Filter, damit das Netz vollständig aufgebaut wird (inkl. B747 + Einzelflüge).
function globeReplayFilters(year) {
  return {
    hub: "all",
    regions: new Set(Object.keys(REGION_META)),
    fleets: new Set(Object.keys(FLEET_META)),
    direction: "all",
    yearMin: 2001,
    yearMax: year,
    animate: true,
    onlyExtreme: false,
    includeSingles: true,
  };
}

// ----- Segmented Control: Karte ↔ Globus -----
function GlobeViewToggle({ view, setView }) {
  const ok = globeSupported();
  const base = "font-mono text-[10px] tracking-[0.2em] uppercase px-3 py-1.5 transition-colors";
  return (
    <div className="inline-flex border border-cream/20 rounded-sm overflow-hidden bg-night/70 backdrop-blur-sm">
      <button
        type="button"
        onClick={() => setView("map")}
        className={`${base} ${view === "map" ? "bg-amber text-night" : "text-cream/70 hover:text-amber"}`}
      >Karte</button>
      <button
        type="button"
        onClick={() => ok && setView("globe")}
        disabled={!ok}
        title={ok ? "3D-Nachtglobus" : "WebGL nicht verfügbar"}
        className={`${base} ${view === "globe" ? "bg-amber text-night" : ok ? "text-cream/70 hover:text-amber" : "text-cream/30 cursor-not-allowed"}`}
      >Globus</button>
    </div>
  );
}

// ----- Der Globus selbst -----
function GlobeCanvas({ filteredRoutes, allRoutes, filters, setFilters, hovered, setHovered, pinned, setPinned, focusCode, fullscreen, onToggleFullscreen }) {
  const wrapRef = _gbR(null);
  const globeRef = _gbR(null);
  const [ready, setReady] = _gbS(false);
  const [libErr, setLibErr] = _gbS(false);
  const [activeMs, setActiveMs] = _gbS(null);
  const [replayYear, setReplayYear] = _gbS(null); // null = Jahres-Stepper inaktiv (volle Ansicht)
  const [spin, setSpin] = _gbS(true); // Auto-Rotation des Globus

  // Refs für Accessor-Funktionen (Restyle ohne Daten-Transition)
  const hoverRef = _gbR(null); hoverRef.current = hovered;
  const pinRef = _gbR(null); pinRef.current = pinned;

  const supported = globeSupported();

  // Flughäfen + Bewegungszahlen aus den gefilterten Routen ableiten
  const points = _gbM(() => {
    const m = new Map();
    filteredRoutes.forEach((r) => {
      [r.a, r.b].forEach((ap) => {
        if (!ap || ap.lat == null) return;
        const cur = m.get(ap.code) || { code: ap.code, lat: ap.lat, lng: ap.lon, stadt: ap.stadt, land: ap.land, mov: 0 };
        cur.mov += r.n;
        m.set(ap.code, cur);
      });
    });
    return [...m.values()];
  }, [filteredRoutes]);

  const arcColorFn = (d) => {
    const sel = pinRef.current || hoverRef.current;
    const c = (REGION_META[d.region] || {}).color || "#f9b000";
    if (sel && sel.key !== d.key) return [c + "12", c + "26"];
    if (sel && sel.key === d.key) return ["#ffffffcc", "#ffd066"];
    return [c + "33", c + "ff"];
  };
  const arcStrokeFn = (d) => {
    const sel = pinRef.current || hoverRef.current;
    const base = Math.max(0.28, Math.sqrt(d.n) * 0.15);
    return sel && sel.key === d.key ? base * 1.8 : base;
  };

  // ----- Init (einmal pro Mount) -----
  _gbE(() => {
    if (!supported) return;
    let dead = false;
    ensureGlobeLib().then(() => {
      if (dead || !wrapRef.current || globeRef.current) return;
      const el = wrapRef.current;
      const rect = el.getBoundingClientRect();
      const w = Globe()(el)
        .width(rect.width).height(rect.height)
        .globeImageUrl(GLOBE_TX + "earth-night.jpg")
        .bumpImageUrl(GLOBE_TX + "earth-topology.png")
        .backgroundImageUrl(GLOBE_TX + "night-sky.png")
        .showAtmosphere(true)
        .atmosphereColor("#6ea2ff")
        .atmosphereAltitude(0.18)
        .arcStartLat((d) => d.a.lat).arcStartLng((d) => d.a.lon)
        .arcEndLat((d) => d.b.lat).arcEndLng((d) => d.b.lon)
        .arcColor(arcColorFn)
        .arcStroke(arcStrokeFn)
        .arcAltitudeAutoScale(0.45)
        .arcDashLength(0.42)
        .arcDashGap(0.16)
        .arcDashInitialGap((d) => ((d.a.lon + 180) / 360))
        .arcDashAnimateTime((d) => 1800 + d.distance / 3)
        .arcsTransitionDuration(700)
        .arcLabel((d) =>
          `<div style="font-family:'JetBrains Mono',monospace;font-size:11px;background:rgba(3,12,47,.94);border:1px solid rgba(249,176,0,.4);padding:6px 10px;border-radius:3px;color:#f6f0e2">
            <b style="color:#ffd066">${d.a.stadt} → ${d.b.stadt}</b><br/>
            ${d.from} – ${d.to} · ${d.n}× · ${d.distance.toLocaleString("de-DE")} km</div>`)
        .onArcHover((a) => setHovered(a || null))
        .onArcClick((a) => setPinned(a))
        .pointLat((d) => d.lat).pointLng((d) => d.lng)
        .pointColor(() => "#ffd066")
        .pointAltitude(0.006)
        .pointRadius((d) => 0.11 + Math.sqrt(d.mov) * 0.03)
        .pointLabel((d) =>
          `<div style="font-family:'JetBrains Mono',monospace;font-size:11px;background:rgba(3,12,47,.94);border:1px solid rgba(249,176,0,.4);padding:6px 10px;border-radius:3px;color:#f6f0e2">
            <b style="color:#ffd066">${d.stadt}</b> · ${d.code}<br/>${d.mov} Bewegungen</div>`)
        .ringColor(() => (t) => `rgba(249,176,0,${1 - t})`)
        .ringMaxRadius(3.2).ringPropagationSpeed(1.6).ringRepeatPeriod(1500)
        .ringLat((d) => d.lat).ringLng((d) => d.lng);

      w.pointOfView({ lat: 35, lng: 15, altitude: 2.2 }, 0);
      const c = w.controls();
      c.autoRotate = true;
      c.autoRotateSpeed = 0.45;
      c.enableDamping = true;
      globeRef.current = w;
      setReady(true);
    }).catch(() => setLibErr(true));
    return () => {
      dead = true;
      if (globeRef.current) {
        globeRef.current._destructor && globeRef.current._destructor();
        globeRef.current = null;
      }
    };
  }, [supported]);

  // ----- Größe an Container koppeln -----
  _gbE(() => {
    const el = wrapRef.current;
    if (!el || !ready || typeof ResizeObserver === "undefined") return;
    const ro = new ResizeObserver((entries) => {
      const w = globeRef.current;
      if (!w) return;
      for (const ent of entries) {
        const { width, height } = ent.contentRect;
        if (width > 0 && height > 0) { w.width(width); w.height(height); }
      }
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, [ready]);

  // ----- Daten nachführen -----
  _gbE(() => {
    const w = globeRef.current;
    if (!w || !ready) return;
    w.arcsData(filteredRoutes);
    w.pointsData(points);
    w.ringsData(points.filter((p) => p.code === "MUC" || p.code === "FRA"));
  }, [filteredRoutes, points, ready]);

  // ----- Restyle bei Hover/Pin + Animations-Toggle -----
  _gbE(() => {
    const w = globeRef.current;
    if (!w || !ready) return;
    w.arcColor((d) => arcColorFn(d));
    w.arcStroke((d) => arcStrokeFn(d));
    if (filters.animate) {
      w.arcDashLength(0.42).arcDashGap(0.16).arcDashAnimateTime((d) => 1800 + d.distance / 3);
    } else {
      w.arcDashLength(1).arcDashGap(0).arcDashAnimateTime(0);
    }
    w.controls().autoRotate = spin && filters.animate && !pinned;
  }, [hovered, pinned, ready, filters.animate, spin]);

  // ----- Eckpunkte-Hover (focusCode) → Kameraflug -----
  _gbE(() => {
    const w = globeRef.current;
    if (!w || !ready || !focusCode) return;
    const ap = airportFull(focusCode);
    if (ap && ap.lat != null) w.pointOfView({ lat: ap.lat, lng: ap.lon, altitude: 1.7 }, 900);
  }, [focusCode, ready]);

  // ----- Jahres-Stepper (manuell vor/zurück durch die Laufbahn) -----
  // yearRef statt State-Closure, damit schnelle Doppelklicks nicht verschluckt werden
  const yearRef = _gbR(null); yearRef.current = replayYear;
  const stepYear = (delta) => {
    setActiveMs(null);
    setPinned(null);
    const cur = yearRef.current;
    const y = Math.max(2001, Math.min(2012,
      cur === null ? (delta > 0 ? 2001 : 2012) : cur + delta));
    yearRef.current = y;
    setReplayYear(y);
    setFilters(globeReplayFilters(y));
    // Bei Milestone-Jahren zur Station fliegen
    const m = GLOBE_MILESTONES.find((mm) => mm.jahr === y);
    const w = globeRef.current;
    if (w && m) w.pointOfView({ lat: m.pov.lat, lng: m.pov.lng, altitude: m.pov.alt }, 1200);
  };

  // ----- Milestone-Kino -----
  const flyMilestone = (m) => {
    const w = globeRef.current;
    setActiveMs(m);
    setReplayYear(m.jahr); // Stepper auf das Milestone-Jahr setzen
    setFilters(globeReplayFilters(m.jahr));
    if (m.code) {
      const route = allRoutes.find((r) => r.to === m.code);
      if (route) setPinned(route);
    } else {
      setPinned(null);
    }
    if (w) w.pointOfView({ lat: m.pov.lat, lng: m.pov.lng, altitude: m.pov.alt }, 1600);
  };

  const replayMs = replayYear !== null ? GLOBE_MILESTONES.find((m) => m.jahr === replayYear) : null;
  const banner = activeMs || replayMs;

  // ----- Fallbacks -----
  if (!supported || libErr) {
    return (
      <div className="ticket-dark border border-cream/15 rounded-sm h-full min-h-[560px] flex items-center justify-center text-center p-8">
        <div>
          <div className="font-mono text-[10px] tracking-[0.25em] uppercase text-amber">Globus nicht verfügbar</div>
          <p className="text-cream/70 text-sm mt-3 max-w-xs">
            {libErr ? "Die 3D-Bibliothek konnte nicht geladen werden." : "Dieser Browser unterstützt kein WebGL."} Die 2D-Karte zeigt dieselben Daten.
          </p>
        </div>
      </div>
    );
  }

  return (
    <div className="relative ticket-dark border border-cream/15 rounded-sm overflow-hidden h-full min-h-[560px]">
      {/* globe.gl mountet hierein */}
      <div ref={wrapRef} className="absolute inset-0" />

      {!ready && (
        <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
          <div className="font-mono text-[10px] tracking-[0.25em] uppercase text-amber animate-pulse">Globus wird geladen …</div>
        </div>
      )}

      {/* Fullscreen-Toggle (wie 2D-Karte, oben rechts) */}
      <button
        type="button"
        onClick={onToggleFullscreen}
        title={fullscreen ? "Vollbild verlassen" : "Vollbild"}
        className="absolute top-3 right-3 z-10 w-8 h-8 flex items-center justify-center rounded-sm border border-cream/20 bg-night/70 text-cream/70 hover:text-amber hover:border-amber transition-colors"
      >
        {fullscreen ? (
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5" />
          </svg>
        ) : (
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" />
          </svg>
        )}
      </button>

      {/* Milestone-Kino: Karriere-Stationen oben */}
      <div className="absolute top-3 left-3 right-14 z-10 flex flex-wrap gap-1.5">
        {GLOBE_MILESTONES.map((m) => (
          <button
            key={m.kurz}
            type="button"
            onClick={() => flyMilestone(m)}
            className={`font-mono text-[9px] tracking-[0.15em] uppercase px-2.5 py-1.5 rounded-sm border transition-colors ${
              activeMs === m
                ? "bg-amber text-night border-amber"
                : "bg-night/70 text-cream/70 border-cream/20 hover:text-amber hover:border-amber"
            }`}
          >{m.kurz}</button>
        ))}
      </div>

      {/* Milestone/Replay-Banner */}
      {banner && (
        <div className="absolute bottom-20 left-1/2 -translate-x-1/2 z-10 max-w-md w-[90%] text-center pointer-events-none">
          <div className="inline-block bg-night/85 border border-amber/40 rounded-sm px-4 py-2.5 backdrop-blur-sm">
            <div className="font-mono text-[9px] tracking-[0.25em] uppercase text-amber">{banner.jahr} · {banner.titel}</div>
            <div className="font-display italic text-cream/85 text-sm mt-1">{banner.text}</div>
          </div>
        </div>
      )}

      {/* Steuerleiste unten: Rotation-Pause + Jahres-Stepper */}
      <div className="absolute bottom-3 left-1/2 -translate-x-1/2 z-10 flex items-center gap-2 bg-night/80 border border-cream/20 rounded-sm px-3 py-2 backdrop-blur-sm">
        <button
          type="button"
          onClick={() => setSpin((s) => !s)}
          title={spin ? "Rotation anhalten" : "Rotation starten"}
          className={`w-8 h-8 flex items-center justify-center rounded-sm border transition-colors ${
            spin ? "border-amber/60 text-amber" : "border-cream/20 text-cream/50 hover:text-amber hover:border-amber"
          }`}
        >
          {spin ? (
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M9 5H6v14h3zM18 5h-3v14h3z" /></svg>
          ) : (
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5v14l12-7z" /></svg>
          )}
        </button>
        <div className="w-px h-6 bg-cream/20" />
        <button
          type="button"
          onClick={() => stepYear(-1)}
          disabled={replayYear === 2001}
          title="Jahr zurück"
          className="w-8 h-8 flex items-center justify-center rounded-sm border border-cream/20 text-cream/70 hover:text-amber hover:border-amber transition-colors disabled:opacity-30 disabled:hover:text-cream/70 disabled:hover:border-cream/20"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6" /></svg>
        </button>
        <div className="font-display text-xl text-cream tabular-nums min-w-[100px] text-center">
          {replayYear !== null ? replayYear : `${filters.yearMin}–${filters.yearMax}`}
        </div>
        <button
          type="button"
          onClick={() => stepYear(1)}
          disabled={replayYear === 2012}
          title="Jahr vor"
          className="w-8 h-8 flex items-center justify-center rounded-sm border border-cream/20 text-cream/70 hover:text-amber hover:border-amber transition-colors disabled:opacity-30 disabled:hover:text-cream/70 disabled:hover:border-cream/20"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18l6-6-6-6" /></svg>
        </button>
      </div>
    </div>
  );
}

Object.assign(window, { GlobeCanvas, GlobeViewToggle, globeSupported });
