#pragma once

#include <cstddef>   // Para size_t
#include <iterator>  // Para pair
#include <map>       // Para map
#include <optional>  // Para optional
#include <string>    // Para string
#include <utility>   // Para pair
#include <vector>    // Para vector

#include "game/entities/balloon.hpp"  // for Balloon

// --- Clase BalloonFormations ---
class BalloonFormations {
   public:
    // --- Estructuras ---
    struct SpawnParams {
        float x = 0;                                  // Posición en el eje X donde crear el globo
        float y = 0;                                  // Posición en el eje Y donde crear el globo
        float vel_x = 0.0F;                           // Velocidad inicial en el eje X
        Balloon::Type type = Balloon::Type::BALLOON;  // Tipo de globo
        Balloon::Size size = Balloon::Size::SMALL;    // Tamaño de globo
        float creation_counter = 0.0F;                // Temporizador para la creación del globo

        // Constructor por defecto
        SpawnParams() = default;

        // Constructor con parámetros
        SpawnParams(float x, float y, float vel_x, Balloon::Type type, Balloon::Size size, float creation_counter)
            : x(x),
              y(y),
              vel_x(vel_x),
              type(type),
              size(size),
              creation_counter(creation_counter) {}
    };

    struct Formation {
        std::vector<SpawnParams> balloons;  // Vector con todas las inicializaciones de los globos de la formación

        // Constructor con parámetros
        Formation(const std::vector<SpawnParams>& spawn_params)
            : balloons(spawn_params) {}

        // Constructor por defecto
        Formation() = default;
    };

    // --- Types ---
    using Pool = std::vector<int>;  // Vector de índices a formaciones

    // --- Constructor y destructor ---
    BalloonFormations() {
        initFormations();
        initFormationPools();
    }
    ~BalloonFormations() = default;

    // --- Getters ---
    auto getPool(int pool_id) -> const Pool& {
        return pools_.at(pool_id);
    }

    auto getFormationFromPool(int pool_id, int formation_index) -> const Formation& {
        int formation_id = pools_.at(pool_id).at(formation_index);
        return formations_.at(formation_id);
    }

    [[nodiscard]] auto getFormation(int formation_id) const -> const Formation& {
        return formations_.at(formation_id);
    }

    // --- Nuevos getters para información de pools ---
    [[nodiscard]] auto getPoolCount() const -> size_t {
        return pools_.size();
    }

    [[nodiscard]] auto getPoolSize(int pool_id) const -> size_t {
        return pools_.at(pool_id).size();
    }

   private:
    // --- Constantes ---
    static constexpr int BALLOON_SPAWN_HEIGHT = 208;        // Altura desde el suelo en la que aparecen los globos
    static constexpr float CREATION_TIME = 5.0F;            // Tiempo base de creación de los globos en segundos (300 frames ÷ 60fps = 5.0s)
    static constexpr float DEFAULT_CREATION_TIME = 3.334F;  // Tiempo base de creación de los globos en segundos (200 frames ÷ 60fps = 3.334s)

    // --- Variables ---
    std::vector<Formation> formations_;  // Vector con todas las formaciones disponibles
    std::vector<Pool> pools_;            // Vector de pools, cada pool contiene índices a formaciones

    // --- Métodos internos ---
    void initFormations();      // Inicializa la lista principal de formaciones de globos disponibles
    void initFormationPools();  // Carga los pools desde archivo de configuración
    auto loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool;
    auto parseBalloonLine(const std::string& line, const std::map<std::string, float>& variables) -> std::optional<SpawnParams>;
    auto loadPoolsFromFile(const std::string& filename) -> bool;                                     // Nueva función para cargar pools
    auto parsePoolLine(const std::string& line) -> std::optional<std::pair<int, std::vector<int>>>;  // Nueva función para parsear líneas de pools
    auto evaluateExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
    auto evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
    static auto trim(const std::string& str) -> std::string;
    void createFloaterVariants();
    void loadDefaultFormations();
    void loadDefaultPools();  // Nueva función para pools por defecto

// --- Depuración (solo en modo DEBUG) ---
#ifdef _DEBUG
    void addTestFormation();
#endif
};