#pragma once

#include <SDL2/SDL.h>
#include "utils.h"
#include "input.h"
#include "animatedsprite.h"

#ifndef PLAYER_H
#define PLAYER_H

// Contadores
#define DEATH_COUNTER 350

// Estados del jugador
#define PLAYER_STATUS_WALKING_LEFT 0
#define PLAYER_STATUS_WALKING_RIGHT 1
#define PLAYER_STATUS_WALKING_STOP 2

#define PLAYER_STATUS_FIRING_UP 0
#define PLAYER_STATUS_FIRING_LEFT 1
#define PLAYER_STATUS_FIRING_RIGHT 2
#define PLAYER_STATUS_FIRING_NO 3

#define PLAYER_ANIMATION_LEGS_WALKING_LEFT 0
#define PLAYER_ANIMATION_LEGS_WALKING_RIGHT 1
#define PLAYER_ANIMATION_LEGS_WALKING_STOP 2

#define PLAYER_ANIMATION_BODY_WALKING_LEFT 0
#define PLAYER_ANIMATION_BODY_FIRING_LEFT 1
#define PLAYER_ANIMATION_BODY_WALKING_RIGHT 2
#define PLAYER_ANIMATION_BODY_FIRING_RIGHT 3
#define PLAYER_ANIMATION_BODY_WALKING_STOP 4
#define PLAYER_ANIMATION_BODY_FIRING_UP 5

#define PLAYER_ANIMATION_HEAD_WALKING_LEFT 0
#define PLAYER_ANIMATION_HEAD_FIRING_LEFT 1
#define PLAYER_ANIMATION_HEAD_WALKING_RIGHT 2
#define PLAYER_ANIMATION_HEAD_FIRING_RIGHT 3
#define PLAYER_ANIMATION_HEAD_WALKING_STOP 4
#define PLAYER_ANIMATION_HEAD_FIRING_UP 5

// Variables del jugador
#define PLAYER_INVULNERABLE_COUNTER 200
#define PLAYER_POWERUP_COUNTER 1500

// Clase Player
class Player
{
private:
	float mPosX; // Posicion en el eje X
	int mPosY;	 // Posicion en el eje Y

	Uint8 mWidth;  // Anchura
	Uint8 mHeight; // Altura

	float mVelX; // Cantidad de pixeles a desplazarse en el eje X
	int mVelY;	 // Cantidad de pixeles a desplazarse en el eje Y

	float mBaseSpeed; // Velocidad base del jugador
	int mCooldown;	  // Contador durante el cual no puede disparar

	Uint32 mScore;			// Puntos del jugador
	float mScoreMultiplier; // Multiplicador de puntos

	Uint8 mStatusWalking; // Estado del jugador
	Uint8 mStatusFiring;  // Estado del jugador

	bool mAlive;				 // Indica si el jugador está vivo
	Uint16 mDeathCounter;		 // Contador para la animación de morirse
	bool mInvulnerable;			 // Indica si el jugador es invulnerable
	Uint16 mInvulnerableCounter; // Contador para la invulnerabilidad
	bool mExtraHit;				 // Indica si el jugador tiene un toque extra
	Uint8 mCoffees;				 // Indica cuantos cafes lleva acumulados
	bool mPowerUp;				 // Indica si el jugador tiene activo el modo PowerUp
	Uint8 mPowerUpHeadOffset;	 // Variable para dibujar la cabeza normal o la del powerup
	bool mInput;				 // Indica si puede recibir ordenes de entrada

	AnimatedSprite *mSpriteLegs;  // Sprite para dibujar las piernas
	AnimatedSprite *mSpriteBody;  // Sprite para dibujar el cuerpo
	AnimatedSprite *mSpriteHead;  // Sprite para dibujar la cabeza
	LTexture *mPlayerDeadTexture; // Textura con los gráficos para la animación de muerte

	circle_t mCollider;	   // Circulo de colisión del jugador
	void shiftColliders(); // Actualiza el circulo de colisión a la posición del jugador

	// Actualiza el valor de la variable
	void updateInvulnerableCounter();

	// Actualiza el valor de la variable
	void updateDeathCounter();

	// Actualiza el valor de la variable
	void updatePowerUpHeadOffset();

public:
	Uint8 mDeathIndex;		// Apaño rapidito. Indice de SmartSprite donde esta ubicado el sprite de morirse
	Uint16 mPowerUpCounter; // Temporizador para el modo PowerUp

	// Constructor
	Player(float x, int y, LTexture *textureLegs, LTexture *textureBody, LTexture *textureHead, LTexture *textureDead, SDL_Renderer *renderer);

	// Destructor
	~Player();

	// Iniciador
	void init();

	// Actua en consecuencia de la entrada recibida
	void setInput(Uint8 input);

	// Mueve el jugador a la posición y animación que le corresponde
	void move();

	// Pinta el jugador en pantalla
	void render();

	// Establece el estado del jugador
	void setWalkingStatus(Uint8 status);

	// Establece el estado del jugador
	void setFiringStatus(Uint8 status);

	// Establece la animación correspondiente al estado
	void setAnimation();

	// Obtiene el valor de la variable
	int getPosX();

	// Obtiene el valor de la variable
	int getPosY();

	// Obtiene el valor de la variable
	int getWidth();

	// Obtiene el valor de la variable
	int getHeight();

	// Indica si el jugador puede disparar
	bool canFire();

	// Establece el valor de la variable
	void setFireCooldown(int time);

	// Actualiza el valor de la variable
	void updateCooldown();

	// Actualiza al jugador a su posicion, animación y controla los contadores
	void update();

	// Obtiene la puntuación del jugador
	Uint32 getScore();

	// Asigna un valor a la puntuación del jugador
	void setScore(Uint32 score);

	// Incrementa la puntuación del jugador
	void addScore(Uint32 score);

	// Obtiene el valor de la variable
	bool isAlive();

	// Establece el valor de la variable
	void setAlive(bool value);

	// Obtiene el valor de la variable
	float getScoreMultiplier();

	// Establece el valor de la variable
	void setScoreMultiplier(float value);

	// Aumenta el valor de la variable hasta un máximo
	void incScoreMultiplier();

	// Decrementa el valor de la variable hasta un mínimo
	void decScoreMultiplier();

	// Obtiene el valor de la variable
	bool isInvulnerable();

	// Establece el valor de la variable
	void setInvulnerable(bool value);

	// Obtiene el valor de la variable
	Uint16 getInvulnerableCounter();

	// Establece el valor de la variable
	void setInvulnerableCounter(Uint16 value);

	// Obtiene el valor de la variable
	bool isPowerUp();

	// Establece el valor de la variable
	void setPowerUp(bool value);

	// Obtiene el valor de la variable
	Uint16 getPowerUpCounter();

	// Establece el valor de la variable
	void setPowerUpCounter(Uint16 value);

	// Actualiza el valor de la variable
	void updatePowerUpCounter();

	// Obtiene el valor de la variable
	bool hasExtraHit();

	// Concede un toque extra al jugador
	void giveExtraHit();

	// Quita el toque extra al jugador
	void removeExtraHit();

	// Habilita la entrada de ordenes
	void enableInput();

	// Deshabilita la entrada de ordenes
	void disableInput();

	// Devuelve el numero de cafes actuales
	Uint8 getCoffees();

	// Obtiene el circulo de colisión
	circle_t &getCollider();

	// Obtiene el puntero a la textura con los gráficos de la animación de morir
	LTexture *getDeadTexture();

	// Obtiene el valor de la variable
	Uint16 getDeathCounter();
};

#endif
