#pragma once

#include <SDL3/SDL_events.h>  // for SDL_Event
#include <SDL3/SDL_render.h>  // for SDL_Renderer
#include <SDL3/SDL_stdinc.h>  // for Uint64
#include <SDL3/SDL_video.h>   // for SDL_Window

#include <array>   // for array
#include <memory>  // for unique_ptr, shared_ptr
#include <string>  // for string
#include <vector>  // for vector

#include "ball.h"                     // for Ball
#include "boids_mgr/boid_manager.h"   // for BoidManager
#include "defines.h"                  // for GravityDirection, ColorTheme, ShapeType
#include "external/texture.h"         // for Texture
#include "input/input_handler.h"      // for InputHandler
#include "scene/scene_manager.h"      // for SceneManager
#include "shapes/shape.h"             // for Shape (interfaz polimórfica)
#include "shapes_mgr/shape_manager.h" // for ShapeManager
#include "state/state_manager.h"      // for StateManager
#include "theme_manager.h"            // for ThemeManager
#include "ui/ui_manager.h"            // for UIManager

class Engine {
    public:
        // Interfaz pública principal
        bool initialize(int width = 0, int height = 0, int zoom = 0, bool fullscreen = false);
        void run();
        void shutdown();

        // === Métodos públicos para InputHandler ===

        // Gravedad y física
        void pushBallsAwayFromGravity();
        void handleGravityToggle();
        void handleGravityDirectionChange(GravityDirection direction, const char* notification_text);

        // Display y depuración
        void toggleVSync();
        void toggleDebug();

        // Figuras 3D
        void toggleShapeMode();
        void activateShape(ShapeType type, const char* notification_text);
        void handleShapeScaleChange(bool increase);
        void resetShapeScale();
        void toggleDepthZoom();

        // Boids (comportamiento de enjambre)
        void toggleBoidsMode();

        // Temas de colores
        void cycleTheme(bool forward);
        void switchThemeByNumpad(int numpad_key);
        void toggleThemePage();
        void pauseDynamicTheme();

        // Sprites/Texturas
        void switchTexture();

        // Escenarios (número de pelotas)
        void changeScenario(int scenario_id, const char* notification_text);

        // Zoom y fullscreen
        void handleZoomIn();
        void handleZoomOut();
        void toggleFullscreen();
        void toggleRealFullscreen();
        void toggleIntegerScaling();

        // Modos de aplicación (DEMO/LOGO)
        void toggleDemoMode();
        void toggleDemoLiteMode();
        void toggleLogoMode();

        // === Métodos públicos para StateManager (callbacks) ===
        // NOTA: StateManager coordina estados, Engine proporciona implementación
        // Estos callbacks permiten que StateManager ejecute acciones complejas que
        // requieren acceso a múltiples componentes (SceneManager, ThemeManager, ShapeManager, etc.)
        // Este enfoque es pragmático y mantiene la separación de responsabilidades limpia
        void performLogoAction(bool logo_waiting_for_flip);
        void executeDemoAction(bool is_lite);
        void executeRandomizeOnDemoStart(bool is_lite);
        void executeToggleGravityOnOff();
        void executeEnterLogoMode(size_t ball_count);
        void executeExitLogoMode();

    private:
        // === Componentes del sistema (Composición) ===
        std::unique_ptr<InputHandler> input_handler_;  // Manejo de entradas SDL
        std::unique_ptr<SceneManager> scene_manager_;  // Gestión de bolas y física
        std::unique_ptr<ShapeManager> shape_manager_;  // Gestión de figuras 3D
        std::unique_ptr<BoidManager> boid_manager_;    // Gestión de comportamiento boids
        std::unique_ptr<StateManager> state_manager_;  // Gestión de estados (DEMO/LOGO)
        std::unique_ptr<UIManager> ui_manager_;        // Gestión de UI (HUD, FPS, notificaciones)

        // Recursos SDL
        SDL_Window* window_ = nullptr;
        SDL_Renderer* renderer_ = nullptr;
        std::shared_ptr<Texture> texture_ = nullptr;      // Textura activa actual
        std::vector<std::shared_ptr<Texture>> textures_;  // Todas las texturas disponibles
        std::vector<std::string> texture_names_;          // Nombres de texturas (sin extensión)
        size_t current_texture_index_ = 0;                // Índice de textura activa
        int current_ball_size_ = 10;                      // Tamaño actual de pelotas (dinámico, se actualiza desde texture)

        // Estado del simulador
        bool should_exit_ = false;

        // Sistema de timing
        Uint64 last_frame_time_ = 0;
        float delta_time_ = 0.0f;

        // Sistema de zoom dinámico
        int current_window_zoom_ = DEFAULT_WINDOW_ZOOM;

        // V-Sync
        bool vsync_enabled_ = true;
        bool fullscreen_enabled_ = false;
        bool real_fullscreen_enabled_ = false;
        ScalingMode current_scaling_mode_ = ScalingMode::INTEGER;  // Modo de escalado actual (F5)

        // Resolución base (configurada por CLI o default)
        int base_screen_width_ = DEFAULT_SCREEN_WIDTH;
        int base_screen_height_ = DEFAULT_SCREEN_HEIGHT;

        // Resolución dinámica actual (cambia en fullscreen real)
        int current_screen_width_ = DEFAULT_SCREEN_WIDTH;
        int current_screen_height_ = DEFAULT_SCREEN_HEIGHT;

        // Resolución física real de ventana/pantalla (para texto absoluto)
        int physical_window_width_ = DEFAULT_SCREEN_WIDTH;
        int physical_window_height_ = DEFAULT_SCREEN_HEIGHT;

        // Sistema de temas (delegado a ThemeManager)
        std::unique_ptr<ThemeManager> theme_manager_;
        int theme_page_ = 0;  // Página actual de temas (0 o 1) para acceso por Numpad

        // Sistema de Figuras 3D (polimórfico)
        // NOTA: Engine mantiene implementación de figuras usada por callbacks DEMO/LOGO
        // ShapeManager tiene implementación paralela para controles manuales del usuario
        SimulationMode current_mode_ = SimulationMode::PHYSICS;
        ShapeType current_shape_type_ = ShapeType::SPHERE;  // Tipo de figura actual
        ShapeType last_shape_type_ = ShapeType::SPHERE;     // Última figura para toggle F
        std::unique_ptr<Shape> active_shape_;               // Puntero polimórfico a figura activa
        float shape_scale_factor_ = 1.0f;                   // Factor de escala manual (Numpad +/-)
        bool depth_zoom_enabled_ = true;                    // Zoom por profundidad Z activado

        // Sistema de Modo DEMO (auto-play) y LOGO
        // NOTA: Engine mantiene estado de implementación para callbacks performLogoAction()
        // StateManager coordina los triggers y timers, Engine ejecuta las acciones
        AppMode previous_app_mode_ = AppMode::SANDBOX;  // Modo previo antes de entrar a LOGO
        float demo_timer_ = 0.0f;                      // Contador de tiempo para próxima acción
        float demo_next_action_time_ = 0.0f;           // Tiempo aleatorio hasta próxima acción (segundos)

        // Sistema de convergencia para LOGO MODE (escala con resolución)
        // Usado por performLogoAction() para detectar cuando las bolas forman el logo
        float shape_convergence_ = 0.0f;            // % de pelotas cerca del objetivo (0.0-1.0)
        float logo_convergence_threshold_ = 0.90f;  // Threshold aleatorio (75-100%)
        float logo_min_time_ = 3.0f;                // Tiempo mínimo escalado con resolución
        float logo_max_time_ = 5.0f;                // Tiempo máximo escalado (backup)

        // Sistema de espera de flips en LOGO MODE (camino alternativo)
        // Permite que LOGO espere a que ocurran rotaciones antes de cambiar estado
        bool logo_waiting_for_flip_ = false;        // true si eligió el camino "esperar flip"
        int logo_target_flip_number_ = 0;           // En qué flip actuar (1, 2 o 3)
        float logo_target_flip_percentage_ = 0.0f;  // % de flip a esperar (0.2-0.8)
        int logo_current_flip_count_ = 0;           // Flips observados hasta ahora

        // Control de entrada manual vs automática a LOGO MODE
        // Determina si LOGO debe salir automáticamente o esperar input del usuario
        bool logo_entered_manually_ = false;        // true si se activó con tecla K, false si automático desde DEMO

        // Estado previo antes de entrar a Logo Mode (para restaurar al salir)
        // Guardado por executeEnterLogoMode(), restaurado por executeExitLogoMode()
        int logo_previous_theme_ = 0;  // Índice de tema (0-9)
        size_t logo_previous_texture_index_ = 0;
        float logo_previous_shape_scale_ = 1.0f;

        // Batch rendering
        std::vector<SDL_Vertex> batch_vertices_;
        std::vector<int> batch_indices_;

        // Configuración del sistema de texto (constantes configurables)
        static constexpr const char* TEXT_FONT_PATH = "data/fonts/determination.ttf";
        static constexpr int TEXT_BASE_SIZE = 24;        // Tamaño base para 240p
        static constexpr bool TEXT_ANTIALIASING = true;  // true = suavizado, false = píxeles nítidos

        // Métodos principales del loop
        void calculateDeltaTime();
        void update();
        void render();

        // Métodos auxiliares privados (llamados por la interfaz pública)
        void showNotificationForAction(const std::string& text);  // Mostrar notificación solo en modo MANUAL

        // Sistema de cambio de sprites dinámico - Métodos privados
        void switchTextureInternal(bool show_notification);  // Implementación interna del cambio de textura

        // Sistema de zoom dinámico - Métodos privados
        int calculateMaxWindowZoom() const;
        void setWindowZoom(int new_zoom);
        void zoomIn();
        void zoomOut();
        void updatePhysicalWindowSize();  // Actualizar tamaño físico real de ventana

        // Rendering
        void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);

        // Sistema de Figuras 3D - Métodos privados
        // NOTA FASE 7: Métodos DUPLICADOS con ShapeManager (Engine mantiene implementación para DEMO/LOGO)
        // TODO FASE 8: Convertir en wrappers puros cuando migremos DEMO/LOGO
        void toggleShapeModeInternal(bool force_gravity_on_exit = true);  // Implementación interna del toggle
        void activateShapeInternal(ShapeType type);                       // Implementación interna de activación
        void updateShape();                                               // Actualizar figura activa
        void generateShape();                                             // Generar puntos de figura activa
        void clampShapeScale();                                           // Limitar escala para evitar clipping
};
