#pragma once

#include <SDL3/SDL.h>  // Para SDL_FRect

#include <array>   // Para array
#include <list>    // Para list
#include <memory>  // Para shared_ptr, unique_ptr
#include <string>  // Para basic_string, string
#include <vector>  // Para vector

#include "game/entities/balloon.hpp"             // for Balloon
#include "game/entities/explosions.hpp"          // for Explosions
#include "game/gameplay/balloon_formations.hpp"  // for BalloonFormations
#include "utils/param.hpp"                       // for Param, ParamGame, param
#include "utils/utils.hpp"                       // for Zone

class IStageInfo;
class Texture;

// --- Types ---
using Balloons = std::list<std::shared_ptr<Balloon>>;

// --- Clase BalloonManager: gestiona todos los globos del juego ---
class BalloonManager {
   public:
    // --- Constructor y destructor ---
    BalloonManager(IStageInfo* stage_info);
    ~BalloonManager() = default;

    // --- Métodos principales ---
    void update(float delta_time);  // Actualiza el estado de los globos (time-based)
    void render();                  // Renderiza los globos en pantalla

    // --- Gestión de globos ---
    void freeBalloons();  // Libera globos que ya no sirven

    // --- Creación de formaciones enemigas ---
    void deployRandomFormation(int stage);            // Crea una formación de globos aleatoria
    void deployFormation(int formation_id);           // Crea una formación específica
    void deployFormation(int formation_id, float y);  // Crea una formación específica con coordenadas

    // --- Creación de globos ---
    auto createBalloon(Balloon::Config config) -> std::shared_ptr<Balloon>;                          // Crea un nuevo globo
    void createChildBalloon(const std::shared_ptr<Balloon>& balloon, const std::string& direction);  // Crea un globo a partir de otro
    void createPowerBall();                                                                          // Crea una PowerBall
    void createTwoBigBalloons();                                                                     // Crea dos globos grandes

    // --- Control de velocidad y despliegue ---
    void setBalloonSpeed(float speed);                                             // Ajusta la velocidad de los globos
    void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; };  // Establece la velocidad base
    void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); };         // Restablece la velocidad de los globos
    void updateBalloonDeployCounter(float delta_time);                             // Actualiza el contador de despliegue (time-based)
    auto canPowerBallBeCreated() -> bool;                                          // Indica si se puede crear una PowerBall
    auto calculateScreenPower() -> int;                                            // Calcula el poder de los globos en pantalla

    // --- Manipulación de globos existentes ---
    auto popBalloon(const std::shared_ptr<Balloon>& balloon) -> int;  // Explosiona un globo, creando otros si aplica
    auto destroyBalloon(std::shared_ptr<Balloon>& balloon) -> int;    // Explosiona un globo sin crear otros
    auto destroyAllBalloons() -> int;                                 // Destruye todos los globos
    void stopAllBalloons();                                           // Detiene el movimiento de los globos
    void startAllBalloons();                                          // Reactiva el movimiento de los globos

    // --- Cambios de apariencia ---
    void reverseColorsToAllBalloons();  // Invierte los colores de los globos
    void normalColorsToAllBalloons();   // Restaura los colores originales

    // --- Configuración de sonido ---
    void setSounds(bool value);          // Activa o desactiva los sonidos de los globos
    void setBouncingSounds(bool value);  // Activa o desactiva los sonidos de rebote los globos
    void setPoppingSounds(bool value);   // Activa o desactiva los sonidos de los globos al explotar

    // --- Configuración de juego ---
    void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; };            // Define el área de juego
    void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; };  // Activa o desactiva el tiempo de creación de globos
    void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; };   // Activa o desactiva la generación de globos

    // --- Getters ---
    auto getMenace() -> int;  // Obtiene el nivel de amenaza generado por los globos
    [[nodiscard]] auto getBalloonSpeed() const -> float { return balloon_speed_; }
    auto getBalloons() -> Balloons& { return balloons_; }
    [[nodiscard]] auto getNumBalloons() const -> int { return balloons_.size(); }

   private:
    // --- Constantes ---
    static constexpr float DEFAULT_BALLOON_DEPLOY_DELAY = 5.0F;  // 300 frames = 5 segundos
    static constexpr float POWERBALL_DEPLOY_DELAY = 0.167F;      // 10 frames = 0.167 segundos
    static constexpr float BALLOON_POP_DELAY = 0.333F;           // 20 frames = 0.333 segundos

    // --- Objetos y punteros ---
    Balloons balloons_;                                            // Vector con los globos activos
    std::unique_ptr<Explosions> explosions_;                       // Objeto para gestionar explosiones
    std::unique_ptr<BalloonFormations> balloon_formations_;        // Objeto para manejar formaciones enemigas
    std::vector<std::shared_ptr<Texture>> balloon_textures_;       // Texturas de los globos
    std::vector<std::shared_ptr<Texture>> explosions_textures_;    // Texturas de explosiones
    std::vector<std::vector<std::string>> balloon_animations_;     // Animaciones de los globos
    std::vector<std::vector<std::string>> explosions_animations_;  // Animaciones de las explosiones
    IStageInfo* stage_info_;                                       // Informacion de la pantalla actual

    // --- Variables de estado ---
    SDL_FRect play_area_ = param.game.play_area.rect;
    float balloon_speed_ = Balloon::GAME_TEMPO.at(0);
    float default_balloon_speed_ = Balloon::GAME_TEMPO.at(0);
    float balloon_deploy_counter_ = 0;
    int power_ball_counter_ = 0;
    int last_balloon_deploy_ = 0;
    bool power_ball_enabled_ = false;
    bool creation_time_enabled_ = true;
    bool can_deploy_balloons_ = true;
    bool bouncing_sound_enabled_ = false;  // Si debe sonar el globo al rebotar
    bool poping_sound_enabled_ = true;     // Si debe sonar el globo al explotar
    bool sound_enabled_ = true;            // Indica si los globos deben hacer algun sonido

    // --- Métodos internos ---
    void init();
};
