"use client";

import React, { useRef, useEffect } from "react";
import { Canvas, useFrame, useThree } from "@react-three/fiber";
import { EffectComposer, Bloom } from "@react-three/postprocessing";
import { KernelSize } from "postprocessing";
import { COLORS } from "./constants";
import { damp, lerp } from "./math";
import HologramCity from "./HologramCity";
import RouteSystem from "./RouteSystem";
import VehicleFleet from "./VehicleFleet";
import AICore from "./AICore";

type Props = {
  progress: React.RefObject<number>;
  reduced?: boolean;
  isMobile?: boolean;
  isTablet?: boolean;
  /** Pause the render loop when the section is scrolled off-screen. */
  active?: boolean;
};

/**
 * Device-specific camera framing. The mobile/tablet scene renders into a much
 * smaller, near-square block than the desktop full-screen card, so the camera
 * is pulled back, raised, and widened (higher fov) to keep every node in frame
 * without clipping. `lerp(start, end, progress)` eases from the chaotic wide
 * view to the settled framing as the narrative progresses.
 */
type CameraFraming = {
  radiusStart: number;
  radiusEnd: number;
  heightStart: number;
  heightEnd: number;
  lookAtY: number;
  fov: number;
};

const FRAMING: Record<"desktop" | "tablet" | "mobile", CameraFraming> = {
  desktop: { radiusStart: 17, radiusEnd: 13, heightStart: 9, heightEnd: 6.5, lookAtY: 2.4, fov: 50 },
  tablet: { radiusStart: 19, radiusEnd: 15, heightStart: 9.5, heightEnd: 7, lookAtY: 2.6, fov: 54 },
  // Mobile: pulled ~33% closer (radius 18→12) and lower, centred on the depot
  // with a tighter fov so the route hub fills the small frame and the empty grid
  // around it is cropped out — the depot → routes → vehicles story reads at 320px.
  mobile: { radiusStart: 16, radiusEnd: 12, heightStart: 8.5, heightEnd: 6, lookAtY: 2.3, fov: 58 },
};

/** Slow cinematic camera move from a high chaotic view to a settled framing. */
function CameraRig({ progress, framing }: { progress: React.RefObject<number>; framing: CameraFraming }) {
  const eased = useRef(0);
  const camera = useThree((s) => s.camera);

  // Re-frame on device change (orientation / breakpoint crossing): the fov is a
  // construction-time prop on <Canvas>, so update it imperatively here.
  useEffect(() => {
    if ("fov" in camera) {
      // eslint-disable-next-line react-hooks/immutability
      (camera as THREE_PerspectiveCamera).fov = framing.fov;
      (camera as THREE_PerspectiveCamera).updateProjectionMatrix();
    }
  }, [camera, framing.fov]);

  useFrame((state, dt) => {
    const p = progress.current ?? 0;
    eased.current = damp(eased.current, p, 1.5, dt);
    const e = eased.current;
    const t = state.clock.elapsedTime;

    const radius = lerp(framing.radiusStart, framing.radiusEnd, e);
    const angle = lerp(-0.5, 0.45, e) + t * 0.02;
    const height = lerp(framing.heightStart, framing.heightEnd, e) + Math.sin(t * 0.4) * 0.3;

    const cam = state.camera;
    cam.position.x = Math.sin(angle) * radius;
    cam.position.z = Math.cos(angle) * radius;
    cam.position.y = height;
    cam.lookAt(0, framing.lookAtY, 0);
  });
  return null;
}

// Minimal structural type so we can set fov without importing three's types here.
type THREE_PerspectiveCamera = { fov: number; updateProjectionMatrix: () => void };

function OptimizationCanvas({ progress, reduced = false, isMobile = false, isTablet = false, active = true }: Props) {
  const cityCount = isMobile ? 48 : 90;
  const framing = isMobile ? FRAMING.mobile : isTablet ? FRAMING.tablet : FRAMING.desktop;

  return (
    <Canvas
      flat
      dpr={[1, isMobile || reduced ? 1.25 : 1.5]}
      camera={{ position: [0, framing.heightStart, framing.radiusStart], fov: framing.fov, near: 0.1, far: 120 }}
      gl={{ antialias: !isMobile, powerPreference: "high-performance", alpha: false }}
      frameloop={active ? "always" : "never"}
    >
      <color attach="background" args={[COLORS.bg]} />
      <fog attach="fog" args={[COLORS.bg, 18, 52]} />
      <ambientLight intensity={0.6} />

      <CameraRig progress={progress} framing={framing} />
      <HologramCity progress={progress} count={cityCount} reduced={reduced} />
      <RouteSystem progress={progress} reduced={reduced} isMobile={isMobile} />
      <VehicleFleet progress={progress} reduced={reduced} />
      <AICore progress={progress} reduced={reduced} />

      {/* Bloom is what turns the additive-blended wireframes/beams into a real
          glowing hologram. Skipped under reduced-motion; lighter on mobile. */}
      {!reduced && (
        <EffectComposer multisampling={isMobile ? 0 : 2}>
          <Bloom
            mipmapBlur
            intensity={isMobile ? 0.5 : 1.0}
            luminanceThreshold={0.15}
            luminanceSmoothing={0.04}
            radius={isMobile ? 0.55 : 0.75}
            kernelSize={KernelSize.MEDIUM}
          />
        </EffectComposer>
      )}
    </Canvas>
  );
}

export default React.memo(OptimizationCanvas);
