refactor this code using playerstate: #pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include <Recast/DetourCrowd.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/ext/quaternion_transform.hpp> 
#include <glm/gtx/quaternion.hpp>
#include <iostream>
#include <World.h>

enum class State {
    IDLE,
    WALK,
    JUMP,
    FALL,
    LAND
};

class Player
{
    bool m_isJumping;
    bool m_isFalling;
    float m_jumpVelocity;
    float m_fallVelocity;
    float m_jumpHeight;
    float m_gravity;
    float m_jumpForwardSpeed;


public:
    Player(dtCrowd* crowd, World* world);
    ~Player();

    void Update(float deltaTime);

    void SetRotation(const glm::quat& rotation);
    glm::quat GetRotation() const;

    void SetPosition(const glm::vec3& position);
    glm::vec3 GetPosition() const;

    void SetLookAt(const glm::vec3& target);
    glm::vec3 GetLookAt() const;

    void MoveTo(const glm::vec3& destination);

    void SetServer(uint16_t serverId);
    uint16_t GetServer() const;

    void SetSpeed(const glm::vec3& speed);
    glm::vec3 GetSpeed() const;

    bool CalculatePathTo(const glm::vec3& destination);
    std::pair<glm::vec3, glm::vec3> GetBoundingBox() const;

    void Jump() {
        if (!m_isJumping && !m_isFalling) {
            m_isJumping = true;
            m_jumpVelocity = sqrt(2 * m_gravity * m_jumpHeight);

            // Set a forward speed for the jump (e.g. 4.0f)
            m_jumpForwardSpeed = 4.0f; // Adjust as needed
        }
    }
private:
    dtCrowd* m_crowd;
    glm::quat m_rotation;
    glm::vec3 m_lookAt;
    glm::vec3 m_position;
    uint16_t m_serverId;
    glm::vec3 m_moveSpeed;
    int m_agentIndex;
    bool m_ProcessMoveToPoint;
    World* m_world;
};

// Implementation

inline Player::Player(dtCrowd* crowd, World* world) :
    m_world(world),
    m_crowd(crowd),
    m_rotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)),
    m_lookAt(0.0f),
    m_serverId(0),
    m_moveSpeed(0.0f),
    m_agentIndex(-1),
    m_ProcessMoveToPoint(false),
    m_isJumping(false), m_isFalling(false),
    m_jumpVelocity(0), m_fallVelocity(0), m_jumpHeight(1.0f), m_gravity(9.8f)
{
    if (!crowd)
        return;
    glm::vec3 dimensions(0.5f, 1.8f, 1.0f); // length, height, width
    dtCrowdAgentParams agentParams;
    memset(&agentParams, 0, sizeof(agentParams));
    agentParams.radius = std::max(dimensions.x, dimensions.z) * 0.5f; // Трохи менший радіус
    agentParams.height = dimensions.y;
    agentParams.maxSpeed = 2.5f; // Трохи повільніший
    agentParams.maxAcceleration = 8.0f; // Нижче прискорення
    agentParams.collisionQueryRange = agentParams.radius * 2.0f;
    agentParams.pathOptimizationRange = agentParams.radius * 20.0f;
    agentParams.updateFlags = DT_CROWD_ANTICIPATE_TURNS |
        DT_CROWD_OPTIMIZE_VIS |
        DT_CROWD_OPTIMIZE_TOPO |
        DT_CROWD_SEPARATION |
        DT_CROWD_OBSTACLE_AVOIDANCE;
    agentParams.obstacleAvoidanceType = 0;
    agentParams.separationWeight = 10.0f; // Високе значення для активного розділення
    float pos[3] = { 0.0f, 0.0f, 0.0f };
    m_agentIndex = m_crowd->addAgent(pos, &agentParams);
    if (m_agentIndex == -1)
    {
        std::cout << "Player::Player: m_agentIndex == -1! " << std::endl;
    }
}

inline Player::~Player()
{
    if (m_agentIndex != -1 && m_crowd)
    {
        m_crowd->removeAgent(m_agentIndex);
    }
}

inline void Player::Update(float deltaTime)
{
    glm::vec3 currentPosition = GetPosition();
    glm::vec3 newPosition = currentPosition;
    bool positionChanged = false;

    // Apply gravity and forward movement when jumping or falling
    if (m_isJumping || m_isFalling) {
        // Apply gravity to vertical movement
        if (m_isJumping) {
            m_jumpVelocity -= m_gravity * deltaTime;
            newPosition.y += m_jumpVelocity * deltaTime;

            if (m_jumpVelocity <= 0) {
                m_isJumping = false;
                m_isFalling = true;
            }
        }
        else if (m_isFalling) {
            float fallGravityScale = 2.0f;
            m_fallVelocity = std::min(m_fallVelocity + (m_gravity * fallGravityScale * deltaTime), 30.0f); // Limit the max fall speed
            newPosition.y -= m_fallVelocity * deltaTime;
        }

        // Continue forward movement during the jump and fall
        glm::quat rotation = GetRotation();
        glm::vec3 forward = glm::normalize(rotation * glm::vec3(0, 0, 1)); // Forward direction
        newPosition += forward * m_jumpForwardSpeed * deltaTime;

        positionChanged = true;
    }

    // Check for ground collision
    float rayLength = 3.0f; // Adjust this to match your world's height
    glm::vec3 rayStart = currentPosition + glm::vec3(0, 0.1f, 0);
    glm::vec3 rayEnd = rayStart - glm::vec3(0, rayLength, 0);
    auto hitResult = m_world->RaycastWithPlayerCollision(rayStart, rayEnd, *this);
    if (hitResult) {
        glm::vec3 hitPosition = *hitResult;
        float groundY = hitPosition.y;
        if (newPosition.y <= groundY + 0.1f) {
            newPosition.y = groundY + 0.1f; // Keep slightly above ground
            if (m_isJumping || m_isFalling) {
                m_isJumping = false;
                m_isFalling = false;
                m_fallVelocity = 0;
                positionChanged = true;
            }
        }
    }
    else if (!m_isFalling && !m_isJumping) {
        m_isFalling = true;
        positionChanged = true;
    }

    // Apply the new position
    if (positionChanged) {
        SetPosition(newPosition);
    }
}

inline void Player::SetRotation(const glm::quat& rotation)
{
    m_rotation = rotation;
    // Update look-at based on new rotation
    glm::vec3 currentPos = GetPosition();
    m_lookAt = currentPos + glm::rotate(m_rotation, glm::vec3(0.0f, 0.0f, -1.0f));
}

inline glm::quat Player::GetRotation() const
{
    return m_rotation;
}


inline void Player::SetPosition(const glm::vec3& newPosition)
{
    m_position = newPosition;
}

inline glm::vec3 Player::GetPosition() const
{
    return m_position;
}

inline void Player::SetLookAt(const glm::vec3& target)
{
    m_lookAt = target;
    glm::vec3 currentPos = GetPosition();

    // Calculate direction on XZ plane
    glm::vec3 direction = target - currentPos;
    direction.y = 0.0f; // Ignore Y component
    direction = glm::normalize(direction);

    // Calculate the angle between the forward vector and the direction
    glm::vec3 forward(0.0f, 0.0f, -1.0f); // Assuming forward is -Z
    float angle = std::atan2(direction.x, direction.z);

    // Create a quaternion for rotation around Y-axis
    m_rotation = glm::angleAxis(angle, glm::vec3(0.0f, 1.0f, 0.0f));
}

inline glm::vec3 Player::GetLookAt() const
{
    return m_lookAt;
}

inline void Player::MoveTo(const glm::vec3& destination)
{
    if (m_agentIndex == -1 || !m_crowd) return;

    float pos[3] = { destination.x, destination.y, destination.z };
    m_crowd->requestMoveTarget(m_agentIndex, 0, pos);
}

inline void Player::SetServer(uint16_t serverId)
{
    m_serverId = serverId;
}

inline uint16_t Player::GetServer() const
{
    return m_serverId;
}

inline void Player::SetSpeed(const glm::vec3& speed)
{
    m_moveSpeed = speed;
}

inline glm::vec3 Player::GetSpeed() const
{
    return m_moveSpeed;
}

inline bool Player::CalculatePathTo(const glm::vec3& destination)
{
    //to-do
    if (m_agentIndex == -1 || !m_crowd) return false;

    float pos[3] = { destination.x, destination.y, destination.z };
    return m_crowd->requestMoveTarget(m_agentIndex, 0, pos);
}

inline std::pair<glm::vec3, glm::vec3> Player::GetBoundingBox() const
{
    glm::vec3 dimensions(0.5f, 1.8f, 1.0f); // length, height, width
    glm::vec3 pos = GetPosition();
    glm::quat rotation = GetRotation();

    // Create a rotation matrix from the quaternion
    glm::mat4 rotationMatrix = glm::mat4_cast(rotation);

    // Calculate the new bounding box after rotation
    glm::vec3 corners[8];
    corners[0] = glm::vec3(-dimensions.x / 2, -dimensions.y / 2, -dimensions.z / 2);
    corners[1] = glm::vec3(dimensions.x / 2, -dimensions.y / 2, -dimensions.z / 2);
    corners[2] = glm::vec3(-dimensions.x / 2, dimensions.y / 2, -dimensions.z / 2);
    corners[3] = glm::vec3(dimensions.x / 2, dimensions.y / 2, -dimensions.z / 2);
    corners[4] = glm::vec3(-dimensions.x / 2, -dimensions.y / 2, dimensions.z / 2);
    corners[5] = glm::vec3(dimensions.x / 2, -dimensions.y / 2, dimensions.z / 2);
    corners[6] = glm::vec3(-dimensions.x / 2, dimensions.y / 2, dimensions.z / 2);
    corners[7] = glm::vec3(dimensions.x / 2, dimensions.y / 2, dimensions.z / 2);

    glm::vec3 min = pos, max = pos;
    for (int i = 0; i < 8; ++i)
    {
        glm::vec3 rotatedCorner = pos + glm::vec3(rotationMatrix * glm::vec4(corners[i], 1.0f));
        min = glm::min(min, rotatedCorner);
        max = glm::max(max, rotatedCorner);
    }

    return std::make_pair(min, max);
}