<script setup lang="ts">
import type { NeatConfig, NeatController } from "@firecms/neat";

const canvasRef = ref<HTMLCanvasElement | null>(null);
const isLive = ref(false);
const shouldMountBackgroundVideo = ref(false);
const isBackgroundVideoReady = ref(false);
const hasBackgroundVideoError = ref(false);
const config = useRuntimeConfig();
const backgroundPlaybackId = computed(() => (
  String(config.public.muxBackgroundPlaybackId || config.public.muxPlaybackId || "").trim()
));
const backgroundPosterUrl = computed(() => {
  if (!backgroundPlaybackId.value) return "";

  const url = new URL(`https://image.mux.com/${encodeURIComponent(backgroundPlaybackId.value)}/thumbnail.jpg`);
  url.searchParams.set("time", "0.1");
  url.searchParams.set("width", "1600");
  url.searchParams.set("fit_mode", "preserve");
  return url.toString();
});

let gradient: NeatController | null = null;
let heroObserver: IntersectionObserver | null = null;
let motionQuery: MediaQueryList | null = null;
let mobileQuery: MediaQueryList | null = null;
let isVisible = false;
let isInitializing = false;
let initToken = 0;
let revealTimer: number | null = null;
let backgroundVideoTimer: number | null = null;
let backgroundVideoIdleId: number | null = null;

const montereyConfig: NeatConfig = {
  colors: [
    { color: "#130437", enabled: true },
    { color: "#B34BD0", enabled: true },
    { color: "#210751", enabled: true },
    { color: "#3511A5", enabled: true },
    { color: "#8F3E8D", enabled: false },
    { color: "#FF9A9E", enabled: false },
  ],
  speed: 4.8,
  horizontalPressure: 7,
  verticalPressure: 3,
  waveFrequencyX: 0,
  waveFrequencyY: 0,
  waveAmplitude: 0,
  shadows: 4,
  highlights: 0,
  colorBrightness: 1.92,
  colorSaturation: 2.18,
  wireframe: false,
  colorBlending: 9,
  backgroundColor: "#030012",
  backgroundAlpha: 0,
  grainScale: 6,
  grainSparsity: 0,
  grainIntensity: 0.1,
  grainSpeed: 0,
  resolution: 0.32,
  yOffset: 150,
  flowDistortionA: 0.4,
  flowDistortionB: 10,
  flowScale: 3.3,
  flowEase: 0.37,
  enableProceduralTexture: false,
  textureVoidLikelihood: 0.06,
  textureVoidWidthMin: 10,
  textureVoidWidthMax: 500,
  textureBandDensity: 0.8,
  textureColorBlending: 0.06,
  textureSeed: 333,
  textureEase: 0.38,
  proceduralBackgroundColor: "#003FFF",
  textureShapeTriangles: 20,
  textureShapeCircles: 15,
  textureShapeBars: 15,
  textureShapeSquiggles: 10,
  yOffsetWaveMultiplier: 4.5,
  yOffsetColorMultiplier: 4.8,
  yOffsetFlowMultiplier: 5.2,
  flowEnabled: true,
};

function supportsWebGl() {
  try {
    const canvas = document.createElement("canvas");
    const context = canvas.getContext("webgl2") || canvas.getContext("webgl");
    const isSupported = Boolean(context);
    context?.getExtension("WEBGL_lose_context")?.loseContext();
    return isSupported;
  } catch {
    return false;
  }
}

function shouldUseLiveGradient() {
  return Boolean(
    canvasRef.value &&
      isVisible &&
      !motionQuery?.matches &&
      !mobileQuery?.matches &&
      supportsWebGl(),
  );
}

function destroyGradient() {
  initToken += 1;
  if (revealTimer !== null) {
    window.clearTimeout(revealTimer);
    revealTimer = null;
  }
  gradient?.destroy();
  gradient = null;
  isLive.value = false;
}

async function initGradient() {
  if (gradient || isInitializing || !shouldUseLiveGradient()) return;

  const token = initToken;
  isInitializing = true;

  try {
    const { NeatGradient } = await import("@firecms/neat");

    if (token !== initToken || !canvasRef.value || !shouldUseLiveGradient()) return;

    gradient = new NeatGradient({
      ref: canvasRef.value,
      ...montereyConfig,
      resolution: window.devicePixelRatio > 1 ? 0.24 : 0.34,
    });
    revealTimer = window.setTimeout(() => {
      revealTimer = null;
      if (token === initToken && gradient && shouldUseLiveGradient()) {
        isLive.value = true;
      }
    }, 180);
  } catch (error) {
    console.warn("Monterey hero background is unavailable", error);
    destroyGradient();
  } finally {
    isInitializing = false;
  }
}

function syncGradient() {
  if (shouldUseLiveGradient()) {
    void initGradient();
    return;
  }

  destroyGradient();
}

function clearBackgroundVideoSchedule() {
  if (backgroundVideoTimer !== null) {
    window.clearTimeout(backgroundVideoTimer);
    backgroundVideoTimer = null;
  }

  if (backgroundVideoIdleId !== null) {
    const idleWindow = window as Window & { cancelIdleCallback?: (handle: number) => void };
    idleWindow.cancelIdleCallback?.(backgroundVideoIdleId);
    backgroundVideoIdleId = null;
  }
}

function shouldUseBackgroundVideo() {
  return Boolean(
    backgroundPlaybackId.value &&
      isVisible &&
      !motionQuery?.matches &&
      !mobileQuery?.matches &&
      !hasBackgroundVideoError.value,
  );
}

async function mountBackgroundVideo() {
  clearBackgroundVideoSchedule();
  if (shouldMountBackgroundVideo.value || !shouldUseBackgroundVideo()) return;

  try {
    await import("@mux/mux-video");
    if (shouldUseBackgroundVideo()) {
      shouldMountBackgroundVideo.value = true;
    }
  } catch (error) {
    console.warn("Mux hero background video is unavailable", error);
    hasBackgroundVideoError.value = true;
  }
}

function scheduleBackgroundVideo() {
  clearBackgroundVideoSchedule();
  if (shouldMountBackgroundVideo.value || !shouldUseBackgroundVideo()) return;

  const idleWindow = window as Window & {
    requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number;
  };

  if (idleWindow.requestIdleCallback) {
    backgroundVideoIdleId = idleWindow.requestIdleCallback(() => {
      backgroundVideoIdleId = null;
      void mountBackgroundVideo();
    }, { timeout: 1600 });
    return;
  }

  backgroundVideoTimer = window.setTimeout(() => {
    backgroundVideoTimer = null;
    void mountBackgroundVideo();
  }, 450);
}

function stopBackgroundVideo() {
  clearBackgroundVideoSchedule();
  shouldMountBackgroundVideo.value = false;
  isBackgroundVideoReady.value = false;
}

function syncBackgroundVideo() {
  if (shouldUseBackgroundVideo()) {
    scheduleBackgroundVideo();
    return;
  }

  stopBackgroundVideo();
}

function markBackgroundVideoReady() {
  if (!shouldUseBackgroundVideo()) return;
  isBackgroundVideoReady.value = true;
}

function markBackgroundVideoError() {
  hasBackgroundVideoError.value = true;
  stopBackgroundVideo();
}

function syncMotionState() {
  syncGradient();
  syncBackgroundVideo();
}

onMounted(() => {
  motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
  mobileQuery = window.matchMedia("(max-width: 700px)");
  motionQuery.addEventListener("change", syncMotionState);
  mobileQuery.addEventListener("change", syncMotionState);

  heroObserver = new IntersectionObserver(
    ([entry]) => {
      isVisible = Boolean(entry?.isIntersecting);
      syncGradient();
      syncBackgroundVideo();
    },
    { rootMargin: "160px 0px", threshold: 0.01 },
  );

  const target = canvasRef.value?.closest(".cyber-hero");
  if (target) heroObserver.observe(target);
  syncBackgroundVideo();
});

onBeforeUnmount(() => {
  heroObserver?.disconnect();
  motionQuery?.removeEventListener("change", syncMotionState);
  mobileQuery?.removeEventListener("change", syncMotionState);
  stopBackgroundVideo();
  destroyGradient();
});
</script>

<template>
  <div
    class="cyber-hero__monterey"
    :class="{ 'cyber-hero__monterey--live': isLive }"
    aria-hidden="true"
  >
    <div
      class="cyber-hero__monterey-video"
      :class="{ 'cyber-hero__monterey-video--ready': isBackgroundVideoReady }"
      :style="{ '--cyber-monterey-video-poster': backgroundPosterUrl ? `url(${backgroundPosterUrl})` : 'none' }"
    >
      <ClientOnly>
        <mux-video
          v-if="shouldMountBackgroundVideo && backgroundPlaybackId"
          class="cyber-hero__monterey-video-player"
          :class="{ 'cyber-hero__monterey-video-player--ready': isBackgroundVideoReady }"
          :playback-id="backgroundPlaybackId"
          :poster="backgroundPosterUrl || undefined"
          stream-type="on-demand"
          autoplay="muted"
          muted
          loop
          playsinline
          preload="auto"
          max-resolution="720p"
          max-auto-resolution="720p"
          cap-rendition-to-player-size
          disable-tracking
          disable-cookies
          style="--media-object-fit: cover;"
          tabindex="-1"
          metadata-video-id="agent-teams-hero-background"
          metadata-video-title="Agent Teams hero background"
          @canplay="markBackgroundVideoReady"
          @loadeddata="markBackgroundVideoReady"
          @playing="markBackgroundVideoReady"
          @error="markBackgroundVideoError"
        />
      </ClientOnly>
    </div>
    <canvas ref="canvasRef" class="cyber-hero__monterey-canvas" />
  </div>
</template>
