import { useFrame, useThree } from "@react-three/fiber";
import React, { useEffect, useState } from "react";
import { useKeyboardControls } from "@react-three/drei";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useCamMode, useToggleView } from "../../../store/builder/store";

import switchToThirdPerson from "./functions/switchToThirdPerson";
import switchToFirstPerson from "./functions/switchToFirstPerson";
import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys";
import { OrthographicCamera, PerspectiveCamera } from "three";

const CamMode: React.FC = () => {
    const { camMode, setCamMode } = useCamMode();
    const [_, get] = useKeyboardControls();
    const [isTransitioning, setIsTransitioning] = useState(false);
    const state: {
        camera: PerspectiveCamera | OrthographicCamera;
        controls: any;
        gl: { domElement: HTMLElement };
    } = useThree();
    const { toggleView } = useToggleView();
    const [isShiftActive, setIsShiftActive] = useState(false);

    useEffect(() => {
        const handlePointerLockChange = async () => {
            if (document.pointerLockElement && !toggleView) {
                return;
            } else if (camMode === "FirstPerson" && !toggleView) {
                setCamMode("ThirdPerson");
                await switchToThirdPerson(state.controls, state.camera);
            }
        };

        document.addEventListener("pointerlockchange", handlePointerLockChange);

        return () => {
            document.removeEventListener("pointerlockchange", handlePointerLockChange);
        };
    }, [camMode, toggleView, setCamMode, state.controls, state.camera]);

    useEffect(() => {
        const handleKeyPress = async (event: KeyboardEvent) => {
            if (!state.controls) return;

            const keyCombination = detectModifierKeys(event);

            if (keyCombination === "/" && !isTransitioning && !toggleView) {
                setIsTransitioning(true);

                state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse;
                state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse;
                state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse;
                state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse;

                if (camMode === "ThirdPerson") {
                    setCamMode("FirstPerson");
                    await switchToFirstPerson(state.controls, state.camera);
                } else if (camMode === "FirstPerson") {
                    setCamMode("ThirdPerson");
                    await switchToThirdPerson(state.controls, state.camera);
                }

                setIsTransitioning(false);
            }

            if (keyCombination === "Shift") {
                setIsShiftActive(true);
            }
        };

        const handleKeyUp = (event: KeyboardEvent) => {
            if (event.key === "Shift") {
                setIsShiftActive(false);
            }
        };

        state.gl.domElement.addEventListener("keydown", handleKeyPress);
        state.gl.domElement.addEventListener("keyup", handleKeyUp);

        return () => {
            state.gl.domElement.removeEventListener("keydown", handleKeyPress);
            state.gl.domElement.removeEventListener("keyup", handleKeyUp);
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [camMode, isTransitioning, toggleView, state.controls, state.camera, state.gl, setCamMode]);

    useFrame(() => {
        const { forward, backward, left, right } = get();
        if (!state.controls) return;
        if (camMode === "ThirdPerson" || !document.pointerLockElement) return;

        const speedMultiplier = isShiftActive ? CONSTANTS.firstPersonControls.sprintSpeed : CONSTANTS.firstPersonControls.walkSpeed;

        if (forward) {
            state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier, true);
        }
        if (backward) {
            state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier, true);
        }
        if (left) {
            state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier, 0, true);
        }
        if (right) {
            state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier, 0, true);
        }
    });

    return null;
};

export default CamMode;
