#pragma once

#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint16, Uint32
#include <memory>			 // Para shared_ptr, unique_ptr
#include <string>			 // Para string
#include <vector>			 // Para vector
#include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h"			 // Para Circle
class Texture;				 // lines 10-10

// Cantidad de elementos del vector con los valores de la deformación del globo al rebotar
constexpr int MAX_BOUNCE = 10;

// Puntos de globo
constexpr int BALLOON_SCORE[] = {50, 100, 200, 400};
constexpr int BALLOON_POWER[] = {1, 3, 7, 15};
constexpr int BALLOON_MENACE[] = {1, 2, 4, 8};
constexpr int BALLOON_SIZE[] = {10, 16, 26, 46};

// Tamaños de globo
enum class BalloonSize : Uint8
{
	SIZE1 = 0,
	SIZE2 = 1,
	SIZE3 = 2,
	SIZE4 = 3,
};

// Clases de globo
enum class BalloonType : Uint8
{
	BALLOON = 0,
	FLOATER = 1,
	POWERBALL = 2,
};

// Velocidad del globo
constexpr float BALLOON_VELX_POSITIVE = 0.7f;
constexpr float BALLOON_VELX_NEGATIVE = -0.7f;

// Indice para las animaciones de los globos
constexpr int BALLOON_MOVING_ANIMATION = 0;
constexpr int BALLOON_POP_ANIMATION = 1;
constexpr int BALLOON_BORN_ANIMATION = 2;

// Velocidades a las que se mueven los globos
constexpr float BALLOON_SPEED[] = {0.60f, 0.70f, 0.80f, 0.90f, 1.00f};

// PowerBall
constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
constexpr int POWERBALL_COUNTER = 8;

// Clase Balloon
class Balloon
{
private:
	// Estructura para el efecto de los rebotes en los globos
	struct Bouncing
	{
		bool enabled = false; // Si el efecto está activo
		Uint8 counter = 0;	  // Contador para el efecto
		Uint8 speed = 2;	  // Velocidad a la que transcurre el efecto
		float zoomW = 1.0f;	  // Zoom aplicado a la anchura
		float zoomH = 1.0f;	  // Zoom aplicado a la altura
		float despX = 0.0f;	  // Desplazamiento de pixeles en el eje X antes de pintar el objeto con zoom
		float despY = 0.0f;	  // Desplazamiento de pixeles en el eje Y antes de pintar el objeto con zoom

		float w[MAX_BOUNCE] = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; // Vector con los valores de zoom para el ancho del globo
		float h[MAX_BOUNCE] = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; // Vector con los valores de zoom para el alto del globo

		// Constructor por defecto
		Bouncing() = default;

		// Método reset
		void reset()
		{
			counter = 0;
			zoomW = 1.0f;
			zoomH = 1.0f;
			despX = 0.0f;
			despY = 0.0f;
		}
	} bouncing_;

	// Objetos y punteros
	std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo

	// Variables
	float x_;						   // Posición en el eje X
	float y_;						   // Posición en el eje Y
	Uint8 w_;						   // Ancho
	Uint8 h_;						   // Alto
	float vx_;						   // Velocidad en el eje X. Cantidad de pixeles a desplazarse
	float vy_;						   // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
	float gravity_;					   // Aceleración en el eje Y. Modifica la velocidad
	float default_vy_;				   // Velocidad inicial que tienen al rebotar contra el suelo
	float max_vy_;					   // Máxima velocidad que puede alcanzar el objeto en el eje Y
	bool being_created_;			   // Indica si el globo se está creando
	bool enabled_ = true;			   // Indica si el globo esta activo
	bool invulnerable_;				   // Indica si el globo es invulnerable
	bool stopped_;					   // Indica si el globo está parado
	bool use_reversed_colors_ = false; // Indica si se ha de usar el color secundario del globo como color principal
	Circle collider_;				   // Circulo de colisión del objeto
	Uint16 creation_counter_;		   // Temporizador para controlar el estado "creandose"
	Uint16 creation_counter_ini_;	   // Valor inicial para el temporizador para controlar el estado "creandose"
	Uint16 score_;					   // Puntos que da el globo al ser destruido
	BalloonType type_;				   // Clase de globo
	BalloonSize size_;				   // Tamaño del globo
	Uint8 menace_;					   // Cantidad de amenaza que genera el globo
	Uint32 counter_ = 0;			   // Contador interno
	float travel_y_ = 1.0f;			   // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad
	float speed_;					   // Velocidad a la que se mueven los globos
	Uint8 power_;					   // Cantidad de poder que alberga el globo

	// Alinea el circulo de colisión con la posición del objeto globo
	void shiftColliders();

	// Alinea el sprite con la posición del objeto globo
	void shiftSprite();

	// Establece el nivel de zoom del sprite
	void zoomSprite();

	// Activa el efecto
	void enableBounce();

	// Detiene el efecto
	void disableBounce();

	// Aplica el efecto
	void updateBounce();

	// Actualiza los estados del globo
	void updateState();

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

public:
	// Constructor
	Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);

	// Destructor
	~Balloon() = default;

	// Centra el globo en la posición X
	void alignTo(int x);

	// Pinta el globo en la pantalla
	void render();

	// Actualiza la posición y estados del globo
	void move();

	// Deshabilita el globo y pone a cero todos los valores
	void disable();

	// Explosiona el globo
	void pop();

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

	// Detiene el globo
	void stop();

	// Pone el globo en movimiento
	void start();

	// Pone el color alternativo en el globo
	void useReverseColor();

	// Pone el color normal en el globo
	void useNormalColor();

	// Getters
	float getPosX() const;
	float getPosY() const;
	int getWidth() const;
	int getHeight() const;
	BalloonSize getSize() const;
	BalloonType getType() const;
	Uint16 getScore() const;
	Circle &getCollider();
	Uint8 getMenace() const;
	Uint8 getPower() const;
	bool isStopped() const;
	bool isInvulnerable() const;
	bool isBeingCreated() const;
	bool isEnabled() const;
	bool isUsingReversedColor();
	bool canBePopped() const;

	// Setters
	void setVelY(float vel_y);
	void setSpeed(float speed);
	void setInvulnerable(bool value);
};