#include "state_manager.hpp"

#include <algorithm>  // for std::min
#include <array>      // for std::array
#include <cstdlib>    // for rand
#include <vector>     // for std::vector

#include "defines.hpp"                   // for constantes DEMO/LOGO
#include "engine.hpp"                    // for Engine (enter/exitShapeMode, texture)
#include "scene/scene_manager.hpp"       // for SceneManager
#include "shapes/png_shape.hpp"          // for PNGShape flip detection
#include "shapes_mgr/shape_manager.hpp"  // for ShapeManager
#include "theme_manager.hpp"             // for ThemeManager

StateManager::StateManager()
    : engine_(nullptr),
      scene_mgr_(nullptr),
      theme_mgr_(nullptr),
      shape_mgr_(nullptr),
      current_app_mode_(AppMode::SANDBOX),
      previous_app_mode_(AppMode::SANDBOX),
      demo_timer_(0.0f),
      demo_next_action_time_(0.0f),
      logo_convergence_threshold_(0.90f),
      logo_min_time_(3.0f),
      logo_max_time_(5.0f),
      logo_waiting_for_flip_(false),
      logo_target_flip_number_(0),
      logo_target_flip_percentage_(0.0f),
      logo_current_flip_count_(0),
      logo_entered_manually_(false),
      logo_previous_theme_(0),
      logo_previous_texture_index_(0),
      logo_previous_shape_scale_(1.0f) {
}

void StateManager::initialize(Engine* engine, SceneManager* scene_mgr, ThemeManager* theme_mgr, ShapeManager* shape_mgr) {
    engine_ = engine;
    scene_mgr_ = scene_mgr;
    theme_mgr_ = theme_mgr;
    shape_mgr_ = shape_mgr;
}

void StateManager::setLogoPreviousState(int theme, size_t texture_index, float shape_scale) {
    logo_previous_theme_ = theme;
    logo_previous_texture_index_ = texture_index;
    logo_previous_shape_scale_ = shape_scale;
}

// ===========================================================================
// ACTUALIZACIÓN DE ESTADOS
// ===========================================================================

void StateManager::update(float delta_time, float shape_convergence, Shape* active_shape) {  // NOLINT(readability-function-cognitive-complexity)
    if (current_app_mode_ == AppMode::SANDBOX) {
        return;
    }

    demo_timer_ += delta_time;

    bool should_trigger = false;

    if (current_app_mode_ == AppMode::LOGO) {
        if (logo_waiting_for_flip_) {
            // CAMINO B: Esperando a que ocurran flips
            auto* png_shape = dynamic_cast<PNGShape*>(active_shape);

            if (png_shape != nullptr) {
                int current_flip_count = png_shape->getFlipCount();

                logo_current_flip_count_ = std::max(current_flip_count, logo_current_flip_count_);

                if (logo_current_flip_count_ + 1 >= logo_target_flip_number_) {
                    if (png_shape->isFlipping()) {
                        float flip_progress = png_shape->getFlipProgress();
                        if (flip_progress >= logo_target_flip_percentage_) {
                            should_trigger = true;
                        }
                    }
                }
            }
        } else {
            // CAMINO A: Esperar convergencia + tiempo
            bool min_time_reached = demo_timer_ >= logo_min_time_;
            bool max_time_reached = demo_timer_ >= logo_max_time_;
            bool convergence_ok = shape_convergence >= logo_convergence_threshold_;

            should_trigger = (min_time_reached && convergence_ok) || max_time_reached;
        }
    } else {
        should_trigger = demo_timer_ >= demo_next_action_time_;
    }

    if (!should_trigger) {
        return;
    }

    if (current_app_mode_ == AppMode::LOGO) {
        // LOGO MODE: Sistema de acciones variadas con gravedad dinámica
        int action = rand() % 100;

        if (shape_mgr_->isShapeModeActive()) {
            // Logo quieto (formado) → Decidir camino a seguir
            if (logo_waiting_for_flip_) {
                // Ya estábamos esperando flips → hacer el cambio SHAPE → PHYSICS
                if (action < 50) {
                    engine_->exitShapeMode(true);  // Con gravedad ON
                } else {
                    engine_->exitShapeMode(false);  // Con gravedad OFF
                }

                logo_waiting_for_flip_ = false;
                logo_current_flip_count_ = 0;

                demo_timer_ = 0.0f;
                float interval_range = logo_max_time_ - logo_min_time_;
                demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
            } else if (rand() % 100 < LOGO_FLIP_WAIT_PROBABILITY) {
                // CAMINO B (50%): Esperar flips
                logo_waiting_for_flip_ = true;
                logo_target_flip_number_ = LOGO_FLIP_WAIT_MIN + rand() % (LOGO_FLIP_WAIT_MAX - LOGO_FLIP_WAIT_MIN + 1);
                logo_target_flip_percentage_ = LOGO_FLIP_TRIGGER_MIN + (rand() % 1000) / 1000.0f * (LOGO_FLIP_TRIGGER_MAX - LOGO_FLIP_TRIGGER_MIN);
                logo_current_flip_count_ = 0;

                auto* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
                if (png_shape != nullptr) {
                    png_shape->resetFlipCount();
                }
                // No hacer nada más — esperar a que ocurran los flips
            } else {
                // CAMINO A (50%): Cambio inmediato
                if (action < 50) {
                    engine_->exitShapeMode(true);  // SHAPE → PHYSICS con gravedad ON
                } else {
                    engine_->exitShapeMode(false);  // SHAPE → PHYSICS con gravedad OFF
                }

                logo_waiting_for_flip_ = false;
                logo_current_flip_count_ = 0;

                demo_timer_ = 0.0f;
                float interval_range = logo_max_time_ - logo_min_time_;
                demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
            }
        } else {
            // Logo animado (PHYSICS) → 4 opciones
            if (action < 50) {
                // 50%: PHYSICS → SHAPE (reconstruir logo)
                engine_->exitShapeMode(false);  // toggleShapeMode: PHYSICS → SHAPE con last_type

                logo_waiting_for_flip_ = false;
                logo_current_flip_count_ = 0;
            } else if (action < 68) {
                // 18%: Forzar gravedad ON
                scene_mgr_->forceBallsGravityOn();
            } else if (action < 84) {
                // 16%: Forzar gravedad OFF
                scene_mgr_->forceBallsGravityOff();
            } else {
                // 16%: Cambiar dirección de gravedad
                auto new_direction = static_cast<GravityDirection>(rand() % 4);
                scene_mgr_->changeGravityDirection(new_direction);
                scene_mgr_->forceBallsGravityOn();
            }

            demo_timer_ = 0.0f;
            float interval_range = logo_max_time_ - logo_min_time_;
            demo_next_action_time_ = logo_min_time_ + (rand() % 1000) / 1000.0f * interval_range;
        }

        // Salir automáticamente si la entrada fue automática (desde DEMO)
        if (!logo_entered_manually_ && rand() % 100 < 60) {
            exitLogoMode(true);  // Volver a DEMO/DEMO_LITE
        }
    } else {
        // DEMO/DEMO_LITE: Acciones normales
        bool is_lite = (current_app_mode_ == AppMode::DEMO_LITE);
        performDemoAction(is_lite);

        demo_timer_ = 0.0f;
        float interval_min = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
        float interval_max = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
        float interval_range = interval_max - interval_min;
        demo_next_action_time_ = interval_min + (rand() % 1000) / 1000.0f * interval_range;
    }
}

void StateManager::setState(AppMode new_mode, int current_screen_width, int current_screen_height) {
    if (current_app_mode_ == new_mode) {
        return;
    }

    if (current_app_mode_ == AppMode::LOGO && new_mode != AppMode::LOGO) {
        previous_app_mode_ = new_mode;
    }

    if (new_mode == AppMode::LOGO) {
        previous_app_mode_ = current_app_mode_;
    }

    current_app_mode_ = new_mode;

    demo_timer_ = 0.0f;

    if (new_mode == AppMode::DEMO || new_mode == AppMode::DEMO_LITE || new_mode == AppMode::LOGO) {
        float min_interval;
        float max_interval;

        if (new_mode == AppMode::LOGO) {
            float resolution_scale = current_screen_height / 720.0f;
            logo_min_time_ = LOGO_ACTION_INTERVAL_MIN * resolution_scale;
            logo_max_time_ = LOGO_ACTION_INTERVAL_MAX * resolution_scale;

            min_interval = logo_min_time_;
            max_interval = logo_max_time_;
        } else {
            bool is_lite = (new_mode == AppMode::DEMO_LITE);
            min_interval = is_lite ? DEMO_LITE_ACTION_INTERVAL_MIN : DEMO_ACTION_INTERVAL_MIN;
            max_interval = is_lite ? DEMO_LITE_ACTION_INTERVAL_MAX : DEMO_ACTION_INTERVAL_MAX;
        }

        demo_next_action_time_ = min_interval + (rand() % 1000) / 1000.0f * (max_interval - min_interval);
    }
}

void StateManager::toggleDemoMode(int current_screen_width, int current_screen_height) {
    if (current_app_mode_ == AppMode::DEMO) {
        setState(AppMode::SANDBOX, current_screen_width, current_screen_height);
    } else {
        setState(AppMode::DEMO, current_screen_width, current_screen_height);
        randomizeOnDemoStart(false);
    }
}

void StateManager::toggleDemoLiteMode(int current_screen_width, int current_screen_height) {
    if (current_app_mode_ == AppMode::DEMO_LITE) {
        setState(AppMode::SANDBOX, current_screen_width, current_screen_height);
    } else {
        setState(AppMode::DEMO_LITE, current_screen_width, current_screen_height);
        randomizeOnDemoStart(true);
    }
}

void StateManager::toggleLogoMode(int current_screen_width, int current_screen_height, size_t ball_count) {
    if (current_app_mode_ == AppMode::LOGO) {
        exitLogoMode(false);
    } else {
        enterLogoMode(false, current_screen_width, current_screen_height, ball_count);
    }
}

// ===========================================================================
// ACCIONES DE DEMO
// ===========================================================================

void StateManager::performDemoAction(bool is_lite) {  // NOLINT(readability-function-cognitive-complexity)
    if ((engine_ == nullptr) || (scene_mgr_ == nullptr) || (theme_mgr_ == nullptr) || (shape_mgr_ == nullptr)) {
        return;
    }

    // ============================================
    // SALTO AUTOMÁTICO A LOGO MODE (Easter Egg)
    // ============================================

    if (is_lite) {
        if (static_cast<int>(scene_mgr_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX] &&
            theme_mgr_->getCurrentThemeIndex() == 5) {  // MONOCHROME
            if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE) {
                enterLogoMode(true, 0, 0, scene_mgr_->getBallCount());
                return;
            }
        }
    } else {
        if (static_cast<int>(scene_mgr_->getBallCount()) >= BALL_COUNT_SCENARIOS[LOGO_MIN_SCENARIO_IDX]) {
            if (rand() % 100 < LOGO_JUMP_PROBABILITY_FROM_DEMO) {
                enterLogoMode(true, 0, 0, scene_mgr_->getBallCount());
                return;
            }
        }
    }

    // ============================================
    // ACCIONES NORMALES DE DEMO/DEMO_LITE
    // ============================================

    int total_weight;
    int random_value;
    int accumulated_weight = 0;

    if (is_lite) {
        total_weight = DEMO_LITE_WEIGHT_GRAVITY_DIR + DEMO_LITE_WEIGHT_GRAVITY_TOGGLE + DEMO_LITE_WEIGHT_SHAPE + DEMO_LITE_WEIGHT_TOGGLE_PHYSICS + DEMO_LITE_WEIGHT_IMPULSE;
        random_value = rand() % total_weight;

        // Cambiar dirección gravedad (25%)
        accumulated_weight += DEMO_LITE_WEIGHT_GRAVITY_DIR;
        if (random_value < accumulated_weight) {
            auto new_direction = static_cast<GravityDirection>(rand() % 4);
            scene_mgr_->changeGravityDirection(new_direction);
            return;
        }

        // Toggle gravedad ON/OFF (20%)
        accumulated_weight += DEMO_LITE_WEIGHT_GRAVITY_TOGGLE;
        if (random_value < accumulated_weight) {
            toggleGravityOnOff();
            return;
        }

        // Activar figura 3D (25%) - PNG_SHAPE excluido
        accumulated_weight += DEMO_LITE_WEIGHT_SHAPE;
        if (random_value < accumulated_weight) {
            constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
            engine_->enterShapeMode(SHAPES[rand() % 8]);
            return;
        }

        // Toggle física ↔ figura (20%)
        accumulated_weight += DEMO_LITE_WEIGHT_TOGGLE_PHYSICS;
        if (random_value < accumulated_weight) {
            engine_->exitShapeMode(false);
            return;
        }

        // Aplicar impulso (10%)
        accumulated_weight += DEMO_LITE_WEIGHT_IMPULSE;
        if (random_value < accumulated_weight) {
            scene_mgr_->pushBallsAwayFromGravity();
            return;
        }

    } else {
        total_weight = DEMO_WEIGHT_GRAVITY_DIR + DEMO_WEIGHT_GRAVITY_TOGGLE + DEMO_WEIGHT_SHAPE + DEMO_WEIGHT_TOGGLE_PHYSICS + DEMO_WEIGHT_REGENERATE_SHAPE + DEMO_WEIGHT_THEME + DEMO_WEIGHT_SCENARIO + DEMO_WEIGHT_IMPULSE + DEMO_WEIGHT_DEPTH_ZOOM + DEMO_WEIGHT_SHAPE_SCALE + DEMO_WEIGHT_SPRITE;
        random_value = rand() % total_weight;

        // Cambiar dirección gravedad (10%)
        accumulated_weight += DEMO_WEIGHT_GRAVITY_DIR;
        if (random_value < accumulated_weight) {
            auto new_direction = static_cast<GravityDirection>(rand() % 4);
            scene_mgr_->changeGravityDirection(new_direction);
            return;
        }

        // Toggle gravedad ON/OFF (8%)
        accumulated_weight += DEMO_WEIGHT_GRAVITY_TOGGLE;
        if (random_value < accumulated_weight) {
            toggleGravityOnOff();
            return;
        }

        // Activar figura 3D (20%) - PNG_SHAPE excluido
        accumulated_weight += DEMO_WEIGHT_SHAPE;
        if (random_value < accumulated_weight) {
            constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
            engine_->enterShapeMode(SHAPES[rand() % 8]);
            return;
        }

        // Toggle física ↔ figura (12%)
        accumulated_weight += DEMO_WEIGHT_TOGGLE_PHYSICS;
        if (random_value < accumulated_weight) {
            engine_->exitShapeMode(false);
            return;
        }

        // Re-generar misma figura (8%)
        accumulated_weight += DEMO_WEIGHT_REGENERATE_SHAPE;
        if (random_value < accumulated_weight) {
            if (shape_mgr_->isShapeModeActive()) {
                shape_mgr_->generateShape();
            }
            return;
        }

        // Cambiar tema (15%)
        accumulated_weight += DEMO_WEIGHT_THEME;
        if (random_value < accumulated_weight) {
            theme_mgr_->switchToTheme(rand() % 15);
            return;
        }

        // Cambiar escenario (10%)
        accumulated_weight += DEMO_WEIGHT_SCENARIO;
        if (random_value < accumulated_weight) {
            int auto_max = std::min(engine_->getMaxAutoScenario(), DEMO_AUTO_MAX_SCENARIO);
            std::vector<int> candidates;
            for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i) {
                candidates.push_back(i);
            }
            if (engine_->isCustomScenarioEnabled() && engine_->isCustomAutoAvailable()) {
                candidates.push_back(CUSTOM_SCENARIO_IDX);
            }
            int new_scenario = candidates[rand() % candidates.size()];
            SimulationMode current_sim_mode = shape_mgr_->getCurrentMode();
            scene_mgr_->changeScenario(new_scenario, current_sim_mode);

            if (shape_mgr_->isShapeModeActive()) {
                shape_mgr_->generateShape();
                scene_mgr_->enableShapeAttractionAll(true);
            }
            return;
        }

        // Aplicar impulso (10%)
        accumulated_weight += DEMO_WEIGHT_IMPULSE;
        if (random_value < accumulated_weight) {
            scene_mgr_->pushBallsAwayFromGravity();
            return;
        }

        // Toggle profundidad (3%)
        accumulated_weight += DEMO_WEIGHT_DEPTH_ZOOM;
        if (random_value < accumulated_weight) {
            if (shape_mgr_->isShapeModeActive()) {
                shape_mgr_->setDepthZoomEnabled(!shape_mgr_->isDepthZoomEnabled());
            }
            return;
        }

        // Cambiar escala de figura (2%)
        accumulated_weight += DEMO_WEIGHT_SHAPE_SCALE;
        if (random_value < accumulated_weight) {
            if (shape_mgr_->isShapeModeActive()) {
                int scale_action = rand() % 3;
                if (scale_action == 0) {
                    shape_mgr_->setShapeScaleFactor(shape_mgr_->getShapeScaleFactor() + SHAPE_SCALE_STEP);
                } else if (scale_action == 1) {
                    shape_mgr_->setShapeScaleFactor(shape_mgr_->getShapeScaleFactor() - SHAPE_SCALE_STEP);
                } else {
                    shape_mgr_->setShapeScaleFactor(SHAPE_SCALE_DEFAULT);
                }
                shape_mgr_->generateShape();
            }
            return;
        }

        // Cambiar sprite (2%)
        accumulated_weight += DEMO_WEIGHT_SPRITE;
        if (random_value < accumulated_weight) {
            engine_->switchTextureSilent();
            return;
        }
    }
}

// ===========================================================================
// RANDOMIZACIÓN AL INICIAR DEMO
// ===========================================================================

void StateManager::randomizeOnDemoStart(bool is_lite) {  // NOLINT(readability-function-cognitive-complexity)
    if ((engine_ == nullptr) || (scene_mgr_ == nullptr) || (theme_mgr_ == nullptr) || (shape_mgr_ == nullptr)) {
        return;
    }

    // Si venimos de LOGO con PNG_SHAPE, cambiar figura obligatoriamente
    if (shape_mgr_->getCurrentShapeType() == ShapeType::PNG_SHAPE) {
        constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
        engine_->enterShapeMode(SHAPES[rand() % 8]);
    }

    if (is_lite) {
        // DEMO LITE: Solo randomizar física/figura + gravedad
        if (rand() % 2 == 0) {
            if (shape_mgr_->isShapeModeActive()) {
                engine_->exitShapeMode(false);
            }
        } else {
            constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
            engine_->enterShapeMode(SHAPES[rand() % 8]);
        }

        auto new_direction = static_cast<GravityDirection>(rand() % 4);
        scene_mgr_->changeGravityDirection(new_direction);
        if (rand() % 2 == 0) {
            toggleGravityOnOff();
        }

    } else {
        // DEMO COMPLETO: Randomizar TODO

        // 1. Física o Figura
        if (rand() % 2 == 0) {
            if (shape_mgr_->isShapeModeActive()) {
                engine_->exitShapeMode(false);
            }
        } else {
            constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
            ShapeType selected_shape = SHAPES[rand() % 8];

            // Randomizar profundidad y escala ANTES de activar la figura
            if (rand() % 2 == 0) {
                shape_mgr_->setDepthZoomEnabled(!shape_mgr_->isDepthZoomEnabled());
            }
            shape_mgr_->setShapeScaleFactor(0.5f + ((rand() % 1500) / 1000.0f));

            engine_->enterShapeMode(selected_shape);
        }

        // 2. Escenario
        int auto_max = std::min(engine_->getMaxAutoScenario(), DEMO_AUTO_MAX_SCENARIO);
        std::vector<int> candidates;
        for (int i = DEMO_AUTO_MIN_SCENARIO; i <= auto_max; ++i) {
            candidates.push_back(i);
        }
        if (engine_->isCustomScenarioEnabled() && engine_->isCustomAutoAvailable()) {
            candidates.push_back(CUSTOM_SCENARIO_IDX);
        }
        int new_scenario = candidates[rand() % candidates.size()];
        SimulationMode current_sim_mode = shape_mgr_->getCurrentMode();
        scene_mgr_->changeScenario(new_scenario, current_sim_mode);

        if (shape_mgr_->isShapeModeActive()) {
            shape_mgr_->generateShape();
            scene_mgr_->enableShapeAttractionAll(true);
        }

        // 3. Tema
        theme_mgr_->switchToTheme(rand() % 15);

        // 4. Sprite
        if (rand() % 2 == 0) {
            engine_->switchTextureSilent();
        }

        // 5. Gravedad
        auto new_direction = static_cast<GravityDirection>(rand() % 4);
        scene_mgr_->changeGravityDirection(new_direction);
        if (rand() % 3 == 0) {
            toggleGravityOnOff();
        }
    }
}

// ===========================================================================
// TOGGLE GRAVEDAD (para DEMO)
// ===========================================================================

void StateManager::toggleGravityOnOff() {
    if (scene_mgr_ == nullptr) {
        return;
    }

    bool gravity_enabled = scene_mgr_->hasBalls() &&
        (scene_mgr_->getFirstBall()->getGravityForce() > 0.0f);

    if (gravity_enabled) {
        scene_mgr_->forceBallsGravityOff();
    } else {
        scene_mgr_->forceBallsGravityOn();
    }
}

// ===========================================================================
// ENTRAR AL MODO LOGO
// ===========================================================================

void StateManager::enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count) {
    if ((engine_ == nullptr) || (scene_mgr_ == nullptr) || (theme_mgr_ == nullptr) || (shape_mgr_ == nullptr)) {
        return;
    }

    logo_entered_manually_ = !from_demo;

    logo_waiting_for_flip_ = false;
    logo_target_flip_number_ = 0;
    logo_target_flip_percentage_ = 0.0f;
    logo_current_flip_count_ = 0;

    // Cambiar a modo LOGO (guarda previous_app_mode_ automáticamente)
    setState(AppMode::LOGO, current_screen_width, current_screen_height);

    // Verificar mínimo de pelotas
    if (scene_mgr_->getCurrentScenario() < LOGO_MIN_SCENARIO_IDX) {
        scene_mgr_->changeScenario(LOGO_MIN_SCENARIO_IDX, shape_mgr_->getCurrentMode());
    }

    // Guardar estado previo (para restaurar al salir)
    logo_previous_theme_ = theme_mgr_->getCurrentThemeIndex();
    logo_previous_texture_index_ = engine_->getCurrentTextureIndex();
    logo_previous_shape_scale_ = shape_mgr_->getShapeScaleFactor();

    // Aplicar textura "small" si existe — buscar por nombre iterando índices
    if (engine_->getCurrentTextureName() != "small") {
        size_t original_idx = logo_previous_texture_index_;
        bool found = false;
        for (size_t i = 0; i < 20; ++i) {
            engine_->setTextureByIndex(i);
            if (engine_->getCurrentTextureName() == "small") {
                found = true;
                break;
            }
            if (engine_->getCurrentTextureName().empty()) {
                break;
            }
        }
        if (!found) {
            engine_->setTextureByIndex(original_idx);
        }
    }

    // Cambiar a tema aleatorio entre: MONOCHROME, LAVENDER, CRIMSON, ESMERALDA
    constexpr std::array<int, 4> LOGO_THEMES = {5, 6, 7, 8};
    theme_mgr_->switchToTheme(LOGO_THEMES[rand() % 4]);

    // Establecer escala a 120%
    shape_mgr_->setShapeScaleFactor(LOGO_MODE_SHAPE_SCALE);

    // Activar PNG_SHAPE (el logo)
    engine_->enterShapeMode(ShapeType::PNG_SHAPE);

    // Configurar PNG_SHAPE en modo LOGO
    auto* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
    if (png_shape != nullptr) {
        png_shape->setLogoMode(true);
        png_shape->resetFlipCount();
    }
}

// ===========================================================================
// SALIR DEL MODO LOGO
// ===========================================================================

void StateManager::exitLogoMode(bool return_to_demo) {
    if (current_app_mode_ != AppMode::LOGO) {
        return;
    }
    if ((engine_ == nullptr) || (scene_mgr_ == nullptr) || (theme_mgr_ == nullptr) || (shape_mgr_ == nullptr)) {
        return;
    }

    logo_entered_manually_ = false;

    // Restaurar estado visual previo
    theme_mgr_->switchToTheme(logo_previous_theme_);
    engine_->setTextureByIndex(logo_previous_texture_index_);
    shape_mgr_->setShapeScaleFactor(logo_previous_shape_scale_);
    shape_mgr_->generateShape();

    // Activar atracción física si estamos en modo SHAPE
    if (shape_mgr_->isShapeModeActive()) {
        scene_mgr_->enableShapeAttractionAll(true);
    }

    // Desactivar modo LOGO en PNG_SHAPE
    auto* png_shape = dynamic_cast<PNGShape*>(shape_mgr_->getActiveShape());
    if (png_shape != nullptr) {
        png_shape->setLogoMode(false);
    }

    // Si la figura activa es PNG_SHAPE, cambiar a otra figura aleatoria
    if (shape_mgr_->getCurrentShapeType() == ShapeType::PNG_SHAPE) {
        constexpr std::array<ShapeType, 8> SHAPES = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
        engine_->enterShapeMode(SHAPES[rand() % 8]);
    }

    if (!return_to_demo) {
        setState(AppMode::SANDBOX, 0, 0);
    } else {
        current_app_mode_ = previous_app_mode_;
    }
}
