import { Capsule, PerspectiveCamera, PointerLockControls } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useContext, useEffect, useRef } from "react";
import { AppContext } from "../App";
import { CapsuleCollider, RapierCollider, RapierRigidBody, RigidBody, useRapier, vec3 } from "@react-three/rapier";
import { quat } from "@react-three/rapier";
import { Euler, Object3D, Vector3 } from "three";
import { useBeforePhysicsStep } from "@react-three/rapier";

const _movespeed = 3.0;

export default function Player() {
    const controlsRef = useRef();
    const { keys } = useContext(AppContext);
    const rapier = useRapier();
    const controller = useRef();
    const collider = useRef();
    const rigidbody = useRef();
    const camera = useRef();

    const refState = useRef({
        grounded: false,
        jumping: false,
        velocity: vec3(),
    });

    useEffect(() => {
        const c = rapier.world.createCharacterController(0.1);
        c.setApplyImpulsesToDynamicBodies(true);
        c.setCharacterMass(0.2);
        controller.current = c;
    }, [rapier]);

    useBeforePhysicsStep((world) => {
        if (controller.current && rigidbody.current && collider.current) {
            const move_axis_x = +(keys.includes('KeyD')) - +(keys.includes('KeyA'));
            const move_axis_z = +(keys.includes('KeyW')) - +(keys.includes('KeyS'));

            const { velocity } = refState.current;
            const position = vec3(rigidbody.current.translation());
            const movement = vec3();

            const forward = new Vector3();
            camera.current.getWorldDirection(forward);
            const left = new Vector3().crossVectors(forward, camera.current.up);

            movement.x += move_axis_z * world.timestep * _movespeed * forward.x;
            movement.z += move_axis_z * world.timestep * _movespeed * forward.z;
            movement.x += move_axis_x * world.timestep * _movespeed * left.x;
            movement.z += move_axis_x * world.timestep * _movespeed * left.z;

            if (refState.current.grounded) {
                velocity.y = 0;
            } else {
                velocity.y -= 9.81 * world.timestep * world.timestep;
            }

            movement.add(velocity);

            controller.current.computeColliderMovement(collider.current, movement);
            refState.current.grounded = controller.current.computedGrounded();

            let correctedMovement = controller.current.computedMovement();
            position.add(vec3(correctedMovement));

            rigidbody.current.setNextKinematicTranslation(position);
        }
    });

    return (
        <RigidBody type="kinematicPosition" colliders={false} ref={rigidbody} position={[0, 2, 0]}>
            <PerspectiveCamera makeDefault position={[0, .9, 0]} fov={90} ref={camera} />
            <PointerLockControls ref={controlsRef} />
            <CapsuleCollider ref={collider} args={[1, 0.5]} />
        </RigidBody>
    );
}

