#pragma once

#include <SDL3/SDL_stdinc.h>  // for Uint64
#include <cstddef>              // for size_t

#include "defines.hpp"  // for AppMode, ShapeType, GravityDirection

// Forward declarations
class Engine;
class Shape;
class PNGShape;
class SceneManager;
class ThemeManager;
class ShapeManager;

/**
 * @class StateManager
 * @brief Gestiona los estados de aplicación (SANDBOX/DEMO/DEMO_LITE/LOGO)
 *
 * Responsabilidad única: Máquina de estados y lógica de modos automáticos
 *
 * Características:
 * - Control de modo DEMO (auto-play completo)
 * - Control de modo DEMO_LITE (solo física/figuras)
 * - Control de modo LOGO (easter egg con convergencia)
 * - Timers y triggers automáticos
 * - Sistema de convergencia y espera de flips
 * - Callbacks al Engine para ejecutar acciones
 */
class StateManager {
    public:
        /**
         * @brief Constructor
         */
        StateManager();

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

        /**
         * @brief Inicializa el StateManager con referencias a los subsistemas necesarios
         * @param engine Puntero al Engine (para cambios de modo y texturas)
         * @param scene_mgr Puntero a SceneManager (para control de bolas/gravedad)
         * @param theme_mgr Puntero a ThemeManager (para cambios de tema)
         * @param shape_mgr Puntero a ShapeManager (para figuras)
         */
        void initialize(Engine* engine, SceneManager* scene_mgr, ThemeManager* theme_mgr, ShapeManager* shape_mgr);

        /**
         * @brief Actualiza la máquina de estados (timers, triggers, acciones)
         * @param delta_time Delta time para timers
         * @param shape_convergence Convergencia actual de la forma (0.0-1.0)
         * @param active_shape Puntero a la forma activa (para flip detection)
         */
        void update(float delta_time, float shape_convergence, Shape* active_shape);

        /**
         * @brief Cambia el estado de aplicación
         * @param new_mode Nuevo modo (SANDBOX/DEMO/DEMO_LITE/LOGO)
         * @param current_screen_width Ancho de pantalla (para escalar tiempos)
         * @param current_screen_height Alto de pantalla (para escalar tiempos)
         */
        void setState(AppMode new_mode, int current_screen_width, int current_screen_height);

        /**
         * @brief Toggle del modo DEMO completo (tecla L)
         * @param current_screen_width Ancho de pantalla
         * @param current_screen_height Alto de pantalla
         */
        void toggleDemoMode(int current_screen_width, int current_screen_height);

        /**
         * @brief Toggle del modo DEMO_LITE (tecla L x2)
         * @param current_screen_width Ancho de pantalla
         * @param current_screen_height Alto de pantalla
         */
        void toggleDemoLiteMode(int current_screen_width, int current_screen_height);

        /**
         * @brief Toggle del modo LOGO (tecla K)
         * @param current_screen_width Ancho de pantalla
         * @param current_screen_height Alto de pantalla
         * @param ball_count Número de bolas actual
         */
        void toggleLogoMode(int current_screen_width, int current_screen_height, size_t ball_count);

        // === Getters ===

        /**
         * @brief Obtiene el modo actual
         */
        AppMode getCurrentMode() const { return current_app_mode_; }

        /**
         * @brief Obtiene el modo previo (antes de LOGO)
         */
        AppMode getPreviousMode() const { return previous_app_mode_; }

        /**
         * @brief Verifica si LOGO está activo
         */
        bool isLogoModeActive() const { return current_app_mode_ == AppMode::LOGO; }

        /**
         * @brief Verifica si DEMO (completo o lite) está activo
         */
        bool isDemoModeActive() const {
            return current_app_mode_ == AppMode::DEMO || current_app_mode_ == AppMode::DEMO_LITE;
        }

        /**
         * @brief Obtiene índice de tema guardado (para restaurar al salir de LOGO)
         */
        int getLogoPreviousTheme() const { return logo_previous_theme_; }

        /**
         * @brief Obtiene índice de textura guardada (para restaurar al salir de LOGO)
         */
        size_t getLogoPreviousTextureIndex() const { return logo_previous_texture_index_; }

        /**
         * @brief Obtiene escala de forma guardada (para restaurar al salir de LOGO)
         */
        float getLogoPreviousShapeScale() const { return logo_previous_shape_scale_; }

        /**
         * @brief Obtiene si LOGO fue activado manualmente (tecla K) o automáticamente (desde DEMO)
         */
        bool getLogoEnteredManually() const { return logo_entered_manually_; }

        /**
         * @brief Establece valores previos de LOGO (llamado por Engine antes de entrar)
         */
        void setLogoPreviousState(int theme, size_t texture_index, float shape_scale);

        /**
         * @brief Entra al modo LOGO (público para permitir salto automático desde DEMO)
         * @param from_demo true si viene desde DEMO, false si es manual
         * @param current_screen_width Ancho de pantalla
         * @param current_screen_height Alto de pantalla
         * @param ball_count Número de bolas
         */
        void enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count);

        /**
         * @brief Sale del modo LOGO (público para permitir salida manual)
         * @param return_to_demo true si debe volver a DEMO/DEMO_LITE
         */
        void exitLogoMode(bool return_to_demo);

    private:
        // === Referencias a subsistemas ===
        Engine* engine_;
        SceneManager* scene_mgr_;
        ThemeManager* theme_mgr_;
        ShapeManager* shape_mgr_;

        // === Estado de aplicación ===
        AppMode current_app_mode_;
        AppMode previous_app_mode_;

        // === Sistema DEMO (timers) ===
        float demo_timer_;
        float demo_next_action_time_;

        // === Sistema LOGO (convergencia) ===
        float logo_convergence_threshold_;
        float logo_min_time_;
        float logo_max_time_;

        // === Sistema LOGO (espera de flips) ===
        bool logo_waiting_for_flip_;
        int logo_target_flip_number_;
        float logo_target_flip_percentage_;
        int logo_current_flip_count_;

        // === Control de entrada LOGO ===
        bool logo_entered_manually_;

        // === Estado previo LOGO (restauración) ===
        int logo_previous_theme_;
        size_t logo_previous_texture_index_;
        float logo_previous_shape_scale_;

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

        /**
         * @brief Ejecuta una acción del modo DEMO
         * @param is_lite true si es DEMO_LITE, false si es DEMO completo
         */
        void performDemoAction(bool is_lite);

        /**
         * @brief Randomiza estado al entrar a modo DEMO
         * @param is_lite true si es DEMO_LITE, false si es DEMO completo
         */
        void randomizeOnDemoStart(bool is_lite);

        /**
         * @brief Toggle de gravedad ON/OFF (para DEMO)
         */
        void toggleGravityOnOff();
};
