import { useRef, useState, type ComponentRef } from "react";
import {
  Canvas,
  useFrame,
  useThree,
  type ThreeEvent,
  useLoader,
} from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import { FBXLoader } from "three/examples/jsm/Addons.js";
import { Vector3 } from "three";

import "./App.css";

const Room = () => {
  const controls = useRef<ComponentRef<typeof OrbitControls>>(null);
  const room = useLoader(FBXLoader, "/room.fbx");
  const [focus, setFocus] = useState<string | null>(null);

  const cameraPosition = useRef<Vector3 | null>(null);
  const cameraTarget = useRef<Vector3>(new Vector3(0, 1, 0));

  const { camera } = useThree();

  useFrame(() => {
    if (!controls.current) return;

    if (cameraPosition.current) {
      camera.position.lerp(cameraPosition.current, 0.09);
      if (camera.position.distanceTo(cameraPosition.current) < 0.012) {
        if (!focus) {
          controls.current.enableZoom = true;
          controls.current.enableRotate = true;
        }

        cameraPosition.current = null;
      }
    }

    controls.current.target.lerp(cameraTarget.current, 0.1);
  });

  const handleClick = (e: ThreeEvent<MouseEvent>) => {
    if (!controls.current) return;

    e.stopPropagation();

    if (e.object.name.includes("Poster") && e.object.name !== focus) {
      const objectPos = new Vector3();
      const objectDir = new Vector3();
      e.object.getWorldPosition(objectPos);
      e.object.getWorldDirection(objectDir);

      cameraPosition.current = objectPos
        .clone()
        .add(objectDir.multiplyScalar(-0.65));
      cameraTarget.current = objectPos;

      controls.current.enableZoom = false;
      controls.current.enableRotate = false;

      setFocus(e.object.name);
    } else if (focus) {
      cameraPosition.current = new Vector3(3, 3, -3);
      cameraTarget.current = new Vector3(0, 1, 0);

      setFocus(null);
    }

    controls.current.update();
  };

  return (
    <>
      <ambientLight intensity={Math.PI / 2} color={"#ffffff"} />
      <directionalLight intensity={5} position={[5, 10, 5]} castShadow />
      <OrbitControls
        ref={controls}
        target={[0, 1, 0]}
        maxPolarAngle={Math.PI / 2}
        enablePan={false}
      />

      <mesh onClick={handleClick}>
        <primitive object={room} />
      </mesh>
    </>
  );
};

export default function App() {
  return (
    <Canvas camera={{ position: [3, 3, -3] }}>
      <Room />
    </Canvas>
  );
}
