#pragma once

#include <cstddef>  // for size_t

#include "defines.hpp"       // for SimulationMode, AppMode
#include "spatial_grid.hpp"  // for SpatialGrid

// Forward declarations
class Engine;
class SceneManager;
class UIManager;
class StateManager;
class Ball;

/**
 * @class BoidManager
 * @brief Gestiona el comportamiento de enjambre (boids)
 *
 * Responsabilidad única: Implementación de algoritmo de boids (Reynolds 1987)
 *
 * Características:
 * - Separación: Evitar colisiones con vecinos cercanos
 * - Alineación: Seguir dirección promedio del grupo
 * - Cohesión: Moverse hacia el centro de masa del grupo
 * - Comportamiento emergente sin control centralizado
 * - Física de steering behavior (velocidad limitada)
 */
class BoidManager {
    public:
        /**
         * @brief Constructor
         */
        BoidManager();

        /**
         * @brief Destructor
         */
        ~BoidManager();

        /**
         * @brief Inicializa el BoidManager con referencias a componentes del Engine
         * @param engine Puntero al Engine (para acceso a recursos)
         * @param scene_mgr Puntero a SceneManager (acceso a bolas)
         * @param ui_mgr Puntero a UIManager (notificaciones)
         * @param state_mgr Puntero a StateManager (estados de aplicación)
         * @param screen_width Ancho de pantalla actual
         * @param screen_height Alto de pantalla actual
         */
        void initialize(Engine* engine, SceneManager* scene_mgr, UIManager* ui_mgr,
                        StateManager* state_mgr, int screen_width, int screen_height);

        /**
         * @brief Actualiza el tamaño de pantalla (llamado en resize/fullscreen)
         * @param width Nuevo ancho de pantalla
         * @param height Nuevo alto de pantalla
         */
        void updateScreenSize(int width, int height);

        /**
         * @brief Activa el modo boids
         */
        void activateBoids();

        /**
         * @brief Desactiva el modo boids (vuelve a física normal)
         * @param force_gravity_on Si debe forzar gravedad ON al salir
         */
        void deactivateBoids(bool force_gravity_on = true);

        /**
         * @brief Toggle entre modo boids y modo física
         * @param force_gravity_on Si debe forzar gravedad ON al salir de boids
         */
        void toggleBoidsMode(bool force_gravity_on = true);

        /**
         * @brief Actualiza el comportamiento de todas las bolas como boids
         * @param delta_time Delta time para física
         */
        void update(float delta_time);

        /**
         * @brief Verifica si el modo boids está activo
         * @return true si modo boids está activo
         */
        bool isBoidsActive() const { return boids_active_; }

    private:
        // Referencias a componentes del Engine
        Engine* engine_;
        SceneManager* scene_mgr_;
        UIManager* ui_mgr_;
        StateManager* state_mgr_;

        // Tamaño de pantalla
        int screen_width_;
        int screen_height_;

        // Estado del modo boids
        bool boids_active_;

        // Spatial Hash Grid para optimización O(n²) → O(n)
        // FASE 2: Grid reutilizable para búsquedas de vecinos
        SpatialGrid spatial_grid_;

        // === Parámetros ajustables en runtime (inicializados con valores de defines.h) ===
        // Permite modificar comportamiento sin recompilar (para tweaking/debug visual)
        float separation_radius_;     // Radio de separación (evitar colisiones)
        float alignment_radius_;      // Radio de alineación (matching de velocidad)
        float cohesion_radius_;       // Radio de cohesión (centro de masa)
        float separation_weight_;     // Peso fuerza de separación (aceleración px/s²)
        float alignment_weight_;      // Peso fuerza de alineación (steering proporcional)
        float cohesion_weight_;       // Peso fuerza de cohesión (aceleración px/s²)
        float max_speed_;             // Velocidad máxima (px/s)
        float min_speed_;             // Velocidad mínima (px/s)
        float max_force_;             // Fuerza máxima de steering (px/s)
        float boundary_margin_;       // Margen para repulsión de bordes (px)
        float boundary_weight_;       // Peso fuerza de repulsión de bordes (aceleración px/s²)

        // Métodos privados para las reglas de Reynolds
        void applySeparation(Ball* boid, float delta_time);
        void applyAlignment(Ball* boid, float delta_time);
        void applyCohesion(Ball* boid, float delta_time);
        void applyBoundaries(Ball* boid);  // Repulsión de bordes (ya no wrapping)
        void limitSpeed(Ball* boid);       // Limitar velocidad máxima
};
