#pragma once

#include <algorithm>  // Para copy
#include <map>        // Para map
#include <optional>   // Para optional
#include <string>     // Para string
#include <vector>     // Para vector

#include "balloon.h"  // Para Balloon::Size, Balloon::Type

// --- Constantes de configuración ---

// --- Estructuras de datos ---
struct BalloonFormationParams {
        int x = 0;                                    // Posición en el eje X donde crear el globo
        int 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
        int creation_counter = 0;                     // Temporizador para la creación del globo

        // Constructor por defecto
        BalloonFormationParams() = default;

        // Constructor con parámetros
        BalloonFormationParams(int x_val, int y_val, float vel_x_val, Balloon::Type type_val, Balloon::Size size_val, int creation_counter_val)
            : x(x_val), y(y_val), vel_x(vel_x_val), type(type_val), size(size_val), creation_counter(creation_counter_val) {}
};

struct BalloonFormationUnit {
        int number_of_balloons;                    // Cantidad de globos que forman la formación
        std::vector<BalloonFormationParams> init;  // Vector con todas las inicializaciones de los globos de la formación

        // Constructor con parámetros
        BalloonFormationUnit(int num_balloons, const std::vector<BalloonFormationParams>& init_params)
            : number_of_balloons(num_balloons), init(init_params) {}

        // Constructor por defecto
        BalloonFormationUnit() : number_of_balloons(0) {}
};

using BalloonFormationPool = std::vector<const BalloonFormationUnit*>;

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

        // --- Getters ---
        auto getPool(int pool) -> const BalloonFormationPool& { return balloon_formation_pool_.at(pool); }
        auto getSet(int pool, int set) -> const BalloonFormationUnit& { return *balloon_formation_pool_.at(pool).at(set); }
        [[nodiscard]] auto getSet(int set) const -> const BalloonFormationUnit& { return balloon_formation_.at(set); }

    private:
        // --- Constantes ---
        static constexpr int BALLOON_SPAWN_HEIGHT = 208;  // Altura desde el suelo en la que aparecen los globos
        static constexpr int CREATION_TIME = 200;         // Tiempo base de creación de los globos para las formaciones
        static constexpr int NUMBER_OF_BALLOON_FORMATIONS = 100;
        static constexpr int MAX_NUMBER_OF_BALLOONS_IN_A_FORMATION = 50;
        static constexpr int NUMBER_OF_SETS_PER_POOL = 10;

        // --- Datos ---
        std::vector<BalloonFormationUnit> balloon_formation_;       // Vector con todas las formaciones enemigas
        std::vector<BalloonFormationPool> balloon_formation_pool_;  // Conjuntos de formaciones enemigas

        // --- Inicialización de formaciones ---
        void initFormations();      // Inicializa la lista principal de formaciones de globos disponibles
        void initFormationPools();  // Prepara las estructuras de agrupamiento o reutilización de formaciones (pools)

        // --- Carga y análisis de datos ---
        auto loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool;                         // Carga las formaciones desde un archivo, evaluando variables dinámicas
        auto parseBalloonLine(const std::string& line, const std::map<std::string, float>& variables) -> std::optional<BalloonFormationParams>;  // Parsea una línea individual del archivo y genera parámetros de formación

        // --- Evaluación de expresiones ---
        auto evaluateExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;        // Evalúa expresiones matemáticas con variables definidas (complejas)
        auto evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;  // Evalúa expresiones más sencillas (sin paréntesis o operadores avanzados)

        // --- Utilidades ---
        static auto trim(const std::string& str) -> std::string;  // Elimina espacios en blanco al inicio y fin de una cadena

        // --- Generación de variantes ---
        void createFloaterVariants();  // Genera variantes de globos flotantes según configuración o aleatoriedad
        void loadDefaultFormations();  // Carga las formaciones por defecto incluidas en el juego si no hay archivo externo

// --- Depuración (solo en modo DEBUG) ---
#ifdef _DEBUG
        void addTestFormation();  // Añade una formación de prueba para debug o validación en tiempo de desarrollo
#endif
};
