#include "baseentity.h"
#include "baseplayer.h"
#include "cglm/io.h"
#include "cglm/vec2.h"
#include "cglm/vec3.h"
#include "console.h"
#include "engine.h"
#include "input.h"
#include "math3d.h"
#include "physics.h"
#include "physics_gen.h"

#define STEP_SIZE 0.3f
#define PLAYER_WIDTH 0.5f
#define PLAYER_HEIGHT 1.8f
#define EPSILON 0.0005f

class CMOBAPlayer: public CBasePlayer
{
public:
	virtual void Precache() override;
	virtual void Spawn( void ) override;
	virtual void Destroy( void ) override;
	virtual void ReadParameter( const char *szName, const char *szValue ) override;
	virtual void Think( float fDelta ) override;

	void Accelerate( void );
	void AirAccelerate( void );
	int ClipVelocity( vec3 in, vec3 normal, vec3 &out, float fOverbounce );
	void FlyMove( void );
	void GroundMove( void );
	void AirMove( void );
	void CategorizePosition( void );
	void Friction( void );
	void PlayerMove( void );


	bool bIsForward = 0;
	bool bIsBack = 0;
	bool bIsLeft = 0;
	bool bIsRight = 0;

	bool bIsJumping = 0;
	bool bIsCrouching = 0;
	bool bIsProning = 0;
	bool bIsFiring = 0;
	bool bIsFiring2 = 0;
	float fStamina;

	float m_fDelta = 0;

	float fPitch = 0;
	float fYaw = 0;
	
	enum {
		PLAYER_GROUNDED,
		PLAYER_FLYING,
	} m_playerState;
	vec3 m_velocity = {0,0,0};
	vec3 m_prevVelocity = {0,0,0};
	
	vec2 forward = {};
	vec2 right = {};

	CPxBoxMesh mesh;
	CPxRigidKinematicPosition rigidbody;
};

void CMOBAPlayer::Precache()
{

}

void CMOBAPlayer::Spawn()
{

};


void CMOBAPlayer::ReadParameter( const char *szName, const char *szValue )
{
	CBaseEntity::ReadParameter(szName, szValue);
}

void CMOBAPlayer::Destroy()
{

}

void CMOBAPlayer::AirAccelerate( void )
{
	m_velocity[2] -= 9.8 * m_fDelta;
}

void CMOBAPlayer::Accelerate( void )
{
	vec2 wishdir = {(float)bIsForward-bIsBack, (float)bIsLeft-bIsRight};
	vec3 velocityDifference;
	vec3 acceleration;
	glm_vec2_rotate(wishdir, fYaw, wishdir);
	glm_vec2_normalize(wishdir);
	for ( int i = 0; i < 2; i++ )
		m_velocity[i] += (wishdir[i]*6 - m_velocity[i]) * m_fDelta/0.25;
}
	
void CMOBAPlayer::Friction( void )
{

};

void CMOBAPlayer::FlyMove( void )
{

}

void CMOBAPlayer::GroundMove( void )
{
	m_velocity[2] = 0;
	Accelerate();
}

void CMOBAPlayer::CategorizePosition( void )
{
	px_vec3 p;
	px_cast_result r;
	p.m[0] = m_position[0];
	p.m[1] = m_position[1];
	p.m[2] = m_position[2];
	r = px_box_cast(px, PLAYER_WIDTH/2, PLAYER_WIDTH/2, PLAYER_HEIGHT/2, p, (px_vec3){}, (px_vec3){0,0,-0.01}, 1);

	if (r.hit)
	{
		m_playerState = PLAYER_GROUNDED;
	} else {
		m_playerState = PLAYER_FLYING;
	}
}

void CMOBAPlayer::PlayerMove( void )
{
	CategorizePosition();

	GroundMove();
	
	vec3 velocity;
	for ( int i = 0; i < 3; i++ )
		velocity[i] = (m_prevVelocity[i] + m_velocity[i]) * 0.5;

	for ( int i = 0; i < 3; i++ )
		m_position[i] += velocity[i] * m_fDelta;

	for ( int i = 0; i < 3; i++ )
		m_prevVelocity[i] = m_velocity[i];

	CategorizePosition();
}

void CMOBAPlayer::Think( float fDelta )
{
	float x = g_fAxisValues[AXIS_MOUSE_X];
	float y = g_fAxisValues[AXIS_MOUSE_Y];
	fPitch = glm_rad(x);
	fYaw = glm_rad(y);

	m_fDelta = fDelta;

	PlayerMove();
};

void PlayerForward(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsForward = true;};
void PlayerForwardUp(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsForward = false;};
void PlayerBack(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsBack = true;};
void PlayerBackUp(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsBack = false;};
void PlayerLeft(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsLeft = true;};
void PlayerLeftUp(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsLeft = false;};
void PlayerRight(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsRight = true;};
void PlayerRightUp(int argc, char **argv) {if (g_localClient.pBasePlayer) ((CMOBAPlayer*)g_localClient.pBasePlayer)->bIsRight = false;};

ConCommand moveForwardCmd("+forward", PlayerForward, 0);
ConCommand moveForwardUpCmd("-forward", PlayerForwardUp, 0);
ConCommand moveBackwardCmd("+back", PlayerBack, 0);
ConCommand moveBackwardUpCmd("-back", PlayerBackUp, 0);
ConCommand moveLeftCmd("+left", PlayerLeft, 0);
ConCommand moveLeftUpCmd("-left", PlayerLeftUp, 0);
ConCommand moveRightCmd("+right", PlayerRight, 0);
ConCommand moveRightUpCmd("-right", PlayerRightUp, 0);

DECLARE_ENTITY(player, CMOBAPlayer);
