#pragma once

#include <memory>  // for unique_ptr

#include "defines.hpp"       // for SimulationMode, ShapeType
#include "shapes/shape.hpp"  // for Shape base class

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

/**
 * @class ShapeManager
 * @brief Gestiona el sistema de figuras 3D (esferas, cubos, PNG shapes, etc.)
 *
 * Responsabilidad única: Gestión de figuras 3D polimórficas
 *
 * Características:
 * - Control de modo simulación (PHYSICS/SHAPE)
 * - Gestión de tipos de figura (SPHERE/CUBE/PYRAMID/TORUS/ICOSAHEDRON/PNG_SHAPE)
 * - Sistema de escalado manual (Numpad +/-)
 * - Toggle de depth zoom (Z)
 * - Generación y actualización de puntos de figura
 * - Callbacks al Engine para renderizado
 */
class ShapeManager {
    public:
        /**
         * @brief Constructor
         */
        ShapeManager();

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

        /**
         * @brief Inicializa el ShapeManager con referencias a otros componentes
         * @param engine Puntero al Engine (para callbacks legacy)
         * @param scene_mgr Puntero a SceneManager (para acceso a bolas)
         * @param ui_mgr Puntero a UIManager (para notificaciones)
         * @param state_mgr Puntero a StateManager (para verificar modo actual)
         * @param screen_width Ancho lógico de pantalla
         * @param screen_height Alto lógico de pantalla
         */
        void initialize(Engine* engine, SceneManager* scene_mgr, UIManager* ui_mgr,
                       StateManager* state_mgr, int screen_width, int screen_height);

        /**
         * @brief Toggle entre modo PHYSICS y SHAPE
         * @param force_gravity_on_exit Forzar gravedad al salir de SHAPE mode
         */
        void toggleShapeMode(bool force_gravity_on_exit = true);

        /**
         * @brief Activa un tipo específico de figura
         * @param type Tipo de figura a activar
         */
        void activateShape(ShapeType type);

        /**
         * @brief Cambia la escala de la figura actual
         * @param increase true para aumentar, false para reducir
         */
        void handleShapeScaleChange(bool increase);

        /**
         * @brief Resetea la escala de figura a 1.0
         */
        void resetShapeScale();

        /**
         * @brief Toggle del zoom por profundidad Z
         */
        void toggleDepthZoom();

        /**
         * @brief Actualiza la figura activa (rotación, etc.)
         * @param delta_time Delta time para animaciones
         */
        void update(float delta_time);

        /**
         * @brief Genera los puntos de la figura activa
         */
        void generateShape();

        // === Getters ===

        /**
         * @brief Obtiene el modo de simulación actual
         */
        SimulationMode getCurrentMode() const { return current_mode_; }

        /**
         * @brief Obtiene el tipo de figura actual
         */
        ShapeType getCurrentShapeType() const { return current_shape_type_; }

        /**
         * @brief Obtiene puntero a la figura activa
         */
        Shape* getActiveShape() { return active_shape_.get(); }
        const Shape* getActiveShape() const { return active_shape_.get(); }

        /**
         * @brief Obtiene el factor de escala actual
         */
        float getShapeScaleFactor() const { return shape_scale_factor_; }

        /**
         * @brief Verifica si depth zoom está activado
         */
        bool isDepthZoomEnabled() const { return depth_zoom_enabled_; }

        /**
         * @brief Verifica si modo SHAPE está activo
         */
        bool isShapeModeActive() const { return current_mode_ == SimulationMode::SHAPE; }

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

        /**
         * @brief Obtiene convergencia actual (para modo LOGO)
         */
        float getConvergence() const { return shape_convergence_; }

        /**
         * @brief Establece la escala de figura y aplica clamping
         * @param scale Nuevo factor de escala (se limitará a rango válido)
         */
        void setShapeScaleFactor(float scale);

        /**
         * @brief Establece el estado del zoom por profundidad Z
         * @param enabled true para activar, false para desactivar
         */
        void setDepthZoomEnabled(bool enabled) { depth_zoom_enabled_ = enabled; }

    private:
        // === Referencias a otros componentes ===
        Engine* engine_;            // Callback al Engine (legacy - temporal)
        SceneManager* scene_mgr_;   // Acceso a bolas y física
        UIManager* ui_mgr_;         // Notificaciones
        StateManager* state_mgr_;   // Verificación de modo actual

        // === Estado de figuras 3D ===
        SimulationMode current_mode_;
        ShapeType current_shape_type_;
        ShapeType last_shape_type_;
        std::unique_ptr<Shape> active_shape_;
        float shape_scale_factor_;
        bool depth_zoom_enabled_;

        // === Dimensiones de pantalla ===
        int screen_width_;
        int screen_height_;

        // === Convergencia (para modo LOGO) ===
        float shape_convergence_;

        // === Métodos privados ===

        /**
         * @brief Implementación interna de activación de figura
         * @param type Tipo de figura
         */
        void activateShapeInternal(ShapeType type);

        /**
         * @brief Limita la escala para evitar clipping
         */
        void clampShapeScale();
};
