#pragma once

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

#include <functional>  // Para function
#include <list>        // Para list
#include <memory>      // Para shared_ptr
#include <vector>      // Para vector

#include "game/entities/bullet.hpp"  // for Bullet

// --- Types ---
using Bullets = std::list<std::shared_ptr<Bullet>>;

// --- Clase BulletManager: gestiona todas las balas del juego ---
//
// Esta clase se encarga de la gestión completa de las balas del juego,
// incluyendo su creación, actualización, renderizado y colisiones.
//
// Funcionalidades principales:
// • Gestión del ciclo de vida: creación, actualización y destrucción de balas
// • Renderizado: dibuja todas las balas activas en pantalla
// • Detección de colisiones: mediante sistema de callbacks
// • Limpieza automática: elimina balas deshabilitadas del contenedor
// • Configuración flexible: permite ajustar parámetros de las balas
//
// La clase utiliza un sistema de callbacks para manejar las colisiones,
// permitiendo que la lógica específica del juego permanezca en Game.
class BulletManager {
   public:
    // --- Types para callbacks ---
    using CollisionCallback = std::function<bool(const std::shared_ptr<Bullet>&)>;
    using OutOfBoundsCallback = std::function<void(const std::shared_ptr<Bullet>&)>;

    // --- Constructor y destructor ---
    BulletManager();
    ~BulletManager() = default;

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

    // --- Gestión de balas ---
    void createBullet(int x, int y, Bullet::Type type, Bullet::Color color, int owner);  // Crea una nueva bala
    void freeBullets();                                                                  // Libera balas que ya no sirven
    void clearAllBullets();                                                              // Elimina todas las balas

    // --- Detección de colisiones ---
    void checkCollisions();                                        // Verifica colisiones de todas las balas
    void setTabeCollisionCallback(CollisionCallback callback);     // Establece callback para colisión con Tabe
    void setBalloonCollisionCallback(CollisionCallback callback);  // Establece callback para colisión con globos
    void setOutOfBoundsCallback(OutOfBoundsCallback callback);     // Establece callback para balas fuera de límites

    // --- Configuración ---
    void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; };  // Define el área de juego

    // --- Getters ---
    auto getBullets() -> Bullets& { return bullets_; }                           // Obtiene referencia al vector de balas
    [[nodiscard]] auto getNumBullets() const -> int { return bullets_.size(); }  // Obtiene el número de balas activas

   private:
    // --- Objetos y punteros ---
    Bullets bullets_;  // Vector con las balas activas

    // --- Variables de configuración ---
    SDL_FRect play_area_;  // Área de juego para límites

    // --- Callbacks para colisiones ---
    CollisionCallback tabe_collision_callback_;     // Callback para colisión con Tabe
    CollisionCallback balloon_collision_callback_;  // Callback para colisión con globos
    OutOfBoundsCallback out_of_bounds_callback_;    // Callback para balas fuera de límites

    // --- Métodos internos ---
    void processBulletUpdate(const std::shared_ptr<Bullet>& bullet, float delta_time);            // Procesa actualización individual
    [[nodiscard]] auto isBulletOutOfBounds(const std::shared_ptr<Bullet>& bullet) const -> bool;  // Verifica si la bala está fuera de límites
};