#pragma once

#include <SDL3/SDL_rect.h>	 // Para SDL_FRect
#include <SDL3/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;

// --- Constantes relacionadas con globos ---
constexpr int MAX_BOUNCE = 10; // Cantidad de elementos del vector de deformación

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, 48, 49};
const std::string BALLOON_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};

enum class BalloonSize : Uint8
{
	SIZE1 = 0,
	SIZE2 = 1,
	SIZE3 = 2,
	SIZE4 = 3,
};

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

constexpr float BALLOON_VELX_POSITIVE = 0.7f;
constexpr float BALLOON_VELX_NEGATIVE = -0.7f;

constexpr int BALLOON_MOVING_ANIMATION = 0;
constexpr int BALLOON_POP_ANIMATION = 1;
constexpr int BALLOON_BORN_ANIMATION = 2;

constexpr float BALLOON_SPEED[] = {0.60f, 0.70f, 0.80f, 0.90f, 1.00f};

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

// --- Clase Balloon ---
class Balloon
{
public:
	// --- Constructores y destructor ---
	Balloon(
		float x,
		float y,
		BalloonType type,
		BalloonSize size,
		float vel_x,
		float speed,
		Uint16 creation_timer,
		SDL_FRect play_area,
		std::shared_ptr<Texture> texture,
		const std::vector<std::string> &animation);
	~Balloon() = default;

	// --- Métodos principales ---
	void alignTo(int x); // Centra el globo en la posición X
	void render();		 // Pinta el globo en la pantalla
	void move();		 // Actualiza la posición y estados del globo
	void update();		 // Actualiza el globo (posición, animación, contadores)
	void stop();		 // Detiene el globo
	void start();		 // Pone el globo en movimiento

	// --- Métodos de color ---
	void useReverseColor(); // Pone el color alternativo en el globo
	void useNormalColor();	// Pone el color normal en el globo

	// --- Getters ---
	float getPosX() const { return x_; }
	float getPosY() const { return y_; }
	int getWidth() const { return w_; }
	int getHeight() const { return h_; }
	BalloonSize getSize() const { return size_; }
	BalloonType getType() const { return type_; }
	Uint16 getScore() const { return score_; }
	Circle &getCollider() { return collider_; }
	Uint8 getMenace() const { return isEnabled() ? menace_ : 0; }
	Uint8 getPower() const { return power_; }
	bool isStopped() const { return stopped_; }
	bool isPowerBall() const { return type_ == BalloonType::POWERBALL; }
	bool isInvulnerable() const { return invulnerable_; }
	bool isBeingCreated() const { return being_created_; }
	bool isEnabled() const { return enabled_; }
	bool isUsingReversedColor() { return use_reversed_colors_; }
	bool canBePopped() const { return !isBeingCreated(); }

	// --- Setters ---
	void setVelY(float vel_y) { vy_ = vel_y; }
	void setSpeed(float speed) { speed_ = speed; }
	void setInvulnerable(bool value) { invulnerable_ = value; }
	void setSound(bool value) { sound_enabled_ = value; }
	void disable() { enabled_ = false; }

private:
	// --- Estructura para el efecto de rebote ---
	struct Bouncing
	{
		bool enabled = false; // Si el efecto está activo
		Uint8 counter = 0;	  // Contador para el efecto
		Uint8 speed = 2;	  // Velocidad del efecto
		float zoomW = 1.0f;	  // Zoom en anchura
		float zoomH = 1.0f;	  // Zoom en altura
		float despX = 0.0f;	  // Desplazamiento X antes de pintar
		float despY = 0.0f;	  // Desplazamiento Y antes de pintar

		float w[MAX_BOUNCE] = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; // Zoom ancho
		float h[MAX_BOUNCE] = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; // Zoom alto

		Bouncing() = default;
		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 de estado y físicas ---
	float x_;						   // Posición X
	float y_;						   // Posición Y
	float w_;						   // Ancho
	float h_;						   // Alto
	float vx_;						   // Velocidad X
	float vy_;						   // Velocidad Y
	float gravity_;					   // Aceleración en Y
	float default_vy_;				   // Velocidad inicial al rebotar
	float max_vy_;					   // Máxima velocidad en Y
	bool being_created_;			   // Si el globo se está creando
	bool enabled_ = true;			   // Si el globo está activo
	bool invulnerable_;				   // Si el globo es invulnerable
	bool stopped_;					   // Si el globo está parado
	bool use_reversed_colors_ = false; // Si se usa el color alternativo
	Circle collider_;				   // Círculo de colisión
	Uint16 creation_counter_;		   // Temporizador de creación
	Uint16 creation_counter_ini_;	   // Valor inicial del temporizador de creación
	Uint16 score_;					   // Puntos al destruir el globo
	BalloonType type_;				   // Tipo de globo
	BalloonSize size_;				   // Tamaño de globo
	Uint8 menace_;					   // Amenaza que genera el globo
	Uint32 counter_ = 0;			   // Contador interno
	float travel_y_ = 1.0f;			   // Distancia a recorrer en Y antes de aplicar gravedad
	float speed_;					   // Velocidad del globo
	Uint8 power_;					   // Poder que alberga el globo
	SDL_FRect play_area_;			   // Zona de movimiento del globo
	std::string sound_;				   // Archivo de sonido al rebotar
	bool sound_enabled_ = false;	   // Si debe sonar el globo al rebotar

	// --- Métodos internos ---
	void shiftColliders(); // Alinea el círculo de colisión
	void shiftSprite();	   // Alinea el sprite
	void zoomSprite();	   // Establece el nivel de zoom del sprite
	void enableBounce();   // Activa el efecto de rebote
	void disableBounce();  // Detiene el efecto de rebote
	void updateBounce();   // Aplica el efecto de rebote
	void updateState();	   // Actualiza los estados del globo
	void setAnimation();   // Establece la animación correspondiente
	void playSound();	   // Reproduce el sonido al rebotar
};