// debris_manager.hpp - Gestor de fragments de explosions
// © 2026 JailDesigner

#pragma once

#include <SDL3/SDL.h>

#include <array>
#include <functional>
#include <memory>
#include <utility>
#include <vector>

#include "core/defaults.hpp"
#include "core/graphics/shape.hpp"
#include "core/rendering/render_context.hpp"
#include "core/types.hpp"
#include "debris.hpp"

namespace Effects {

    // Gestor de fragments de explosions
    // Manté un pool de objectes Debris i gestiona el seu cicle de vida
    class DebrisManager {
       public:
        // Notificació opcional cada vegada que es genera una explosió. El
        // consumidor pot usar-la per fer reaccionar elements del fons (border
        // bumps, pulse del playfield, etc.).
        using ExplosionCallback = std::function<void(Vec2 center)>;

        explicit DebrisManager(Rendering::Renderer* renderer);

        void setExplosionCallback(ExplosionCallback callback) {
            explosion_callback_ = std::move(callback);
        }

        // Crear explosión a partir de una shape
        // - shape: shape vectorial a explode
        // - centro: posición del centro de l'objecte
        // - angle: orientació de l'objecte (radians)
        // - scale: scale de l'objecte (1.0 = normal)
        // - velocitat_base: velocity inicial dels fragments (px/s)
        // - brightness: factor de brightness heretat (0.0-1.0, per defecte 1.0)
        // - velocitat_objecte: velocity de l'objecte que explota (px/s, per defecte 0)
        // - velocitat_angular: velocity angular heretada (rad/s, per defecte 0)
        // - factor_herencia_visual: factor de herència rotación visual (0.0-1.0, per defecte 0.0)
        // - lifetime: temps de vida del debris (s, per defecte TEMPS_VIDA = 2s)
        // - friction: desacceleració del debris (px/s², per defecte ACCELERACIO = -60)
        // - segment_multiplier: nombre de còpies per segment (per defecte 1 = sense duplicar)
        // - bullet_impulse_velocity: velocitat de la bala que ha causat l'impacte (px/s,
        //   per defecte 0). S'aplica a cada fragment escalada per
        //   Defaults::Physics::Debris::BULLET_IMPULSE_FACTOR, independent de
        //   velocitat_objecte. Permet que els trossos "salten amb la força de la bala"
        //   encara que el cos sigui pesat i amb prou feines es mogui.
        // - piece_scale: multiplicador de la longitud de cada fragment al spawn
        //   (per defecte 1.0). Útil per a debris "parcial" d'impactes no letals
        //   en enemics HP>1 (trossos petits, com d'esquerda).
        void explode(const std::shared_ptr<Graphics::Shape>& shape,
            const Vec2& centro,
            float angle,
            float scale,
            float velocitat_base,
            float brightness = 1.0F,
            const Vec2& velocitat_objecte = {.x = 0.0F, .y = 0.0F},
            float velocitat_angular = 0.0F,
            float factor_herencia_visual = 0.0F,
            // sound: nom del so d'explosió. Cadena buida ("") = explosió silenciosa.
            const std::string& sound = Defaults::Sound::ENEMY_EXPLOSION,
            SDL_Color color = {0, 0, 0, 0},  // alpha==0 → fragmentos usan oscilador global
            float lifetime = Defaults::Physics::Debris::TEMPS_VIDA,
            float friction = Defaults::Physics::Debris::ACCELERACIO,
            int segment_multiplier = 1,
            const Vec2& bullet_impulse_velocity = {.x = 0.0F, .y = 0.0F},
            float piece_scale = 1.0F);

        // Actualitzar todos los fragments active
        void update(float delta_time);

        // Dibuixar todos los fragments active
        void draw() const;

        // Reiniciar todos los fragments (clear)
        void reset();

        // Obtenir número de fragments active
        [[nodiscard]] auto getActiveCount() const -> int;

       private:
        Rendering::Renderer* renderer_;
        ExplosionCallback explosion_callback_;

        // Pool de fragments (màxim concurrent)
        // Pentàgon 5 línies × 15 enemics × multiplier 3 = 225 trossos només d'enemics.
        // + ship (3 línies) + balas (5 línies × 3) = ~243. Arrodonit a 300.
        static constexpr int MAX_DEBRIS = 300;
        std::array<Debris, MAX_DEBRIS> debris_pool_;

        // Trobar primer slot inactiu
        auto findFreeSlot() -> Debris*;

        // Calcular direcció de explosión (radial, des del centro hacia el segment).
        // Estático: solo opera sobre los puntos pasados, sin estado del manager.
        [[nodiscard]] static auto computeExplosionDirection(const Vec2& p1, const Vec2& p2, const Vec2& centre_objecte) -> Vec2;

        // Sub-pasos de explode() (descomposició per reduir complexitat cognitiva).
        // extractSegments y los apply* son static (solo toquen el debris pasado).
        [[nodiscard]] static auto extractSegments(const Graphics::ShapePrimitive& primitive)
            -> std::vector<std::pair<Vec2, Vec2>>;
        // Inicialitza un debris en un slot lliure i el deixa actiu. Retorna
        // false si el pool está ple (la cridadora ha d'aturar el bucle).
        auto spawnDebris(const Vec2& world_p1, const Vec2& world_p2, const Vec2& centro, float velocitat_base, float brightness, const Vec2& velocitat_objecte, float velocitat_angular, float factor_herencia_visual, SDL_Color color, float lifetime, float friction, const Vec2& bullet_impulse_velocity, float piece_scale) -> bool;
        static void applyAngularVelocity(Debris& debris, const Vec2& direccio, float velocitat_angular);
        static void applyVisualRotation(Debris& debris, float velocitat_angular, float factor_herencia_visual);
    };

}  // namespace Effects
