import { CameraControls } from "@react-three/drei";
import { useRef, useEffect } from "react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useToggleView, useResetCamera } from "../../../store/builder/store";
import { useSocketStore } from "../../../store/socket/useSocketStore";
import { useSceneStore } from "../../../store/scene/useSceneStore";

import CamMode from "../camera/camMode";
import SwitchView from "../camera/switchView";
import SyncCam from "../camera/syncCam";
import ContextControls from "./contextControls/contextControls";
import TransformControl from "./transformControls/transformControls";
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D";
import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls";
import UndoRedo3DControls from "./undoRedoControls/undoRedo3D/undoRedo3DControls";
import CameraShortcutsControls from "../camera/shortcutsControls/cameraShortcutsControls";

import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi";
import { setCameraApi } from "../../../services/factoryBuilder/camera/setCameraApi";
import updateCamPosition from "../camera/functions/updateCameraPosition";

export default function Controls() {
    const controlsRef = useRef<CameraControls>(null);
    const state = useThree();
    const { toggleView } = useToggleView();
    const { resetCamera, setResetCamera } = useResetCamera();
    const { camType } = useSceneStore();
    const { builderSocket } = useSocketStore();
    const { projectId } = useParams();
    const { userId, organization } = getUserData();

    useEffect(() => {
        if (controlsRef.current) {
            (controlsRef.current as any).mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
            (controlsRef.current as any).mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
        }

        if (!projectId) return;
        getCameraApi(projectId)
            .then((data) => {
                if (data?.position && data?.target) {
                    controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
                    controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
                } else {
                    controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
                    controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
                }
            })
            .catch((error) => console.error("Failed to fetch camera data:", error));
    }, [projectId]);

    useEffect(() => {
        if (resetCamera && projectId) {
            controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
            controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
            controlsRef.current?.rotateAzimuthTo(CONSTANTS.threeDimension.defaultAzimuth);

            if (!builderSocket?.connected) {
                setCameraApi(
                    projectId,
                    new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
                    new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
                    new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation)
                );
            } else {
                const camData = {
                    organization,
                    userId: userId,
                    position: new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
                    target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
                    rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
                    socketId: builderSocket.id,
                    projectId,
                };
                builderSocket.emit("v1:Camera:set", camData);
            }

            setResetCamera(false);
        }
    }, [resetCamera, builderSocket, projectId]);

    useEffect(() => {
        controlsRef.current?.setBoundary(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)));
        // state.scene.add(new THREE.Box3Helper(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)), 0xffff00));
        let hasInteracted = false;
        let intervalId: NodeJS.Timeout | null = null;

        const handleRest = () => {
            if (hasInteracted && controlsRef.current && state.camera.position && !toggleView && builderSocket && camType === "perspective") {
                const position = state.camera.position;
                if (position.x === 0 && position.y === 0 && position.z === 0) return;
                updateCamPosition(controlsRef, builderSocket, position, state.camera.rotation, projectId);
                stopInterval();
            }
        };

        const startInterval = () => {
            hasInteracted = true;
            if (!intervalId) {
                intervalId = setInterval(() => {
                    if (controlsRef.current && !toggleView && camType === "perspective") {
                        handleRest();
                    }
                }, CONSTANTS.camPositionUpdateInterval);
            }
        };

        const stopInterval = () => {
            if (intervalId) {
                clearInterval(intervalId);
                intervalId = null;
            }
        };

        const controls = controlsRef.current;
        if (controls && !toggleView && camType === "perspective") {
            controls.addEventListener("sleep", handleRest);
            controls.addEventListener("control", startInterval);
            controls.addEventListener("controlend", stopInterval);
        }

        return () => {
            if (controls) {
                controls.removeEventListener("sleep", handleRest);
                controls.removeEventListener("control", startInterval);
                controls.removeEventListener("controlend", stopInterval);
            }
            stopInterval();
        };
    }, [toggleView, state, builderSocket, camType]);

    return (
        <>
            <CameraControls
                makeDefault
                ref={controlsRef}
                minDistance={toggleView || camType === "orthographic" ? CONSTANTS.twoDimension.minDistance : CONSTANTS.threeDimension.minDistance}
                maxDistance={CONSTANTS.thirdPersonControls.maxDistance}
                minZoom={CONSTANTS.thirdPersonControls.minZoom}
                maxZoom={CONSTANTS.thirdPersonControls.maxZoom}
                maxPolarAngle={CONSTANTS.thirdPersonControls.maxPolarAngle}
                camera={state.camera}
                dollyToCursor={toggleView || camType === "orthographic"}
                verticalDragToForward={true}
                boundaryEnclosesCamera={true}
                dollyDragInverted
            >
                <SwitchView />

                <CamMode />

                <CameraShortcutsControls />

                <SyncCam />
            </CameraControls>

            <SelectionControls3D />

            <SelectionControls2D />

            <UndoRedo2DControls />

            <UndoRedo3DControls />

            <TransformControl />

            <ContextControls />
        </>
    );
}
