import { Suspense, useCallback, useEffect } from "react";
import { Canvas, useThree } from "@react-three/fiber";
import { Physics } from "@react-three/rapier";
import * as THREE from "three";
import { DebugPerf } from "@/components/debug/DebugPerf";
import { RepairGame } from "@/components/three/gameplay/RepairGame";
import { logger } from "@/utils/core/Logger";
import type { RepairMissionId } from "@/types/gameplay/repairMission";
import type { Vector3Tuple } from "@/types/three/three";

// Isolated scene — no world offset, no terrain. The repair game runs
// fully centred in its own context so the heavy map never loads here.
const REPAIR_SCENE_POSITION: Vector3Tuple = [0, 0, 0];

// Background: very dark blue-grey to match Altera's night-time mood
const REPAIR_SCENE_BG = "#0b0d14";

// Lighting tuned to match the main world defaults from lightingConfig.ts
const AMBIENT_COLOR = "#dfe7d8";
const AMBIENT_INTENSITY = 0.9;
const SUN_COLOR = "#ffe2bf";
const SUN_INTENSITY = 2.2;
const SUN_POSITION: Vector3Tuple = [5, 8, 4];

// Mimic the first-person view from the main world:
//   - PLAYER_EYE_HEIGHT = 1.75  → camera Y
//   - Case floats at [0, 0.4, 1.8] (inspected) → [0, 1.05, 2.05] (repairing)
//   - Look-at target averaged between those two states
const CAMERA_POSITION: Vector3Tuple = [5, 2, 2];
const CAMERA_LOOK_AT: Vector3Tuple = [0, 0.7, 1.9];

function RepairSceneCamera(): null {
  const { camera } = useThree();

  useEffect(() => {
    camera.lookAt(...CAMERA_LOOK_AT);
  }, [camera]);

  return null;
}

interface RepairGameSceneProps {
  mission: RepairMissionId;
}

export function RepairGameScene({
  mission,
}: RepairGameSceneProps): React.JSX.Element {
  const handleCreated = useCallback(({ gl }: { gl: THREE.WebGLRenderer }) => {
    const canvas = gl.domElement;
    const loseContextExt = gl.getContext().getExtension("WEBGL_lose_context");

    const handleContextLost = (event: Event) => {
      event.preventDefault();
      logger.error("WebGL", "Repair scene context lost — attempting restore");
      window.setTimeout(() => loseContextExt?.restoreContext(), 500);
    };

    const handleContextRestored = () => {
      logger.info("WebGL", "Repair scene context restored");
    };

    canvas.addEventListener("webglcontextlost", handleContextLost);
    canvas.addEventListener("webglcontextrestored", handleContextRestored);
  }, []);

  return (
    <Canvas
      camera={{ position: CAMERA_POSITION, fov: 42 }}
      shadows={{ type: THREE.PCFShadowMap }}
      gl={{
        powerPreference: "high-performance",
        antialias: true,
        stencil: false,
      }}
      onCreated={handleCreated}
    >
      <color attach="background" args={[REPAIR_SCENE_BG]} />

      <RepairSceneCamera />

      {/* Lighting — mirrors the game world defaults */}
      <ambientLight intensity={AMBIENT_INTENSITY} color={AMBIENT_COLOR} />
      <directionalLight
        position={SUN_POSITION}
        intensity={SUN_INTENSITY}
        color={SUN_COLOR}
        castShadow
        shadow-mapSize-width={1024}
        shadow-mapSize-height={1024}
      />

      <Suspense fallback={null}>
        {/* Physics is required: TriggerObject and GrabbableObject both use
            RigidBody. The world is minimal — no octree, no character bodies. */}
        <Physics>
          <RepairGame
            mission={mission}
            position={REPAIR_SCENE_POSITION}
            snapToTerrain={false}
          />
        </Physics>
      </Suspense>

      <DebugPerf />
    </Canvas>
  );
}
