#pragma once

#include <SDL2/SDL.h>
#include "common/animatedsprite.h"
#include "common/asset.h"
#include "common/input.h"
#include "common/texture.h"
#include "common/utils.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

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

// Clase Player
class Player
{
private:
	// Objetos y punteros
	SDL_Renderer *renderer;		 // El renderizador de la ventana
	AnimatedSprite *headSprite;	 // Sprite para dibujar la cabeza
	AnimatedSprite *bodySprite;	 // Sprite para dibujar el cuerpo
	AnimatedSprite *legsSprite;	 // Sprite para dibujar las piernas
	AnimatedSprite *deathSprite; // Sprite para dibujar el jugador derrotado
	AnimatedSprite *fireSprite; // Sprite para dibujar el aura del jugador con el poder a tope

	// Variables
	float posX; // Posicion en el eje X
	int posY;	// Posicion en el eje Y

	Uint8 width;  // Anchura
	Uint8 height; // Altura

	float velX; // Cantidad de pixeles a desplazarse en el eje X
	int velY;	// Cantidad de pixeles a desplazarse en el eje Y

	float baseSpeed; // Velocidad base del jugador
	int cooldown;	 // Contador durante el cual no puede disparar

	Uint32 score;		   // Puntos del jugador
	float scoreMultiplier; // Multiplicador de puntos

	Uint8 statusWalking; // Estado del jugador
	Uint8 statusFiring;	 // Estado del jugador

	bool alive;					// Indica si el jugador está vivo
	Uint16 deathCounter;		// Contador para la animación de morirse
	bool invulnerable;			// Indica si el jugador es invulnerable
	Uint16 invulnerableCounter; // Contador para la invulnerabilidad
	bool extraHit;				// Indica si el jugador tiene un toque extra
	Uint8 coffees;				// Indica cuantos cafes lleva acumulados
	bool powerUp;				// Indica si el jugador tiene activo el modo PowerUp
	Uint16 powerUpCounter;		// Temporizador para el modo PowerUp
	bool input;					// Indica si puede recibir ordenes de entrada
	circle_t collider;			// Circulo de colisión del jugador

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

	// 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:
	// Constructor
	Player(float x, int y, SDL_Renderer *renderer, std::vector<Texture *> texture, std::vector<std::vector<std::string> *> animations);

	// Destructor
	~Player();

	// Iniciador
	void init();

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

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

	// Pone las texturas del jugador
	void setPlayerTextures(std::vector<Texture *> texture);

	// 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();

	// 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();

	// 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
	Texture *getDeadTexture();

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

#endif
