#include "state_manager.h"

#include <cstdlib>  // for rand

#include "../defines.h"  // for constantes DEMO/LOGO
#include "../engine.h"   // for Engine (callbacks)
#include "../shapes/png_shape.h"  // for PNGShape flip detection

StateManager::StateManager()
    : engine_(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) {
}

StateManager::~StateManager() {
}

void StateManager::initialize(Engine* engine) {
    engine_ = engine;
}

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 - Migrado desde Engine::updateDemoMode()
// ===========================================================================

void StateManager::update(float delta_time, float shape_convergence, Shape* active_shape) {
    // Verificar si algún modo demo está activo (DEMO, DEMO_LITE o LOGO)
    if (current_app_mode_ == AppMode::SANDBOX) return;

    // Actualizar timer
    demo_timer_ += delta_time;

    // Determinar si es hora de ejecutar acción (depende del modo)
    bool should_trigger = false;

    if (current_app_mode_ == AppMode::LOGO) {
        // LOGO MODE: Dos caminos posibles
        if (logo_waiting_for_flip_) {
            // CAMINO B: Esperando a que ocurran flips
            // Obtener referencia a PNGShape si está activa
            PNGShape* png_shape = dynamic_cast<PNGShape*>(active_shape);

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

                // Detectar nuevo flip completado
                if (current_flip_count > logo_current_flip_count_) {
                    logo_current_flip_count_ = current_flip_count;
                }

                // Si estamos EN o DESPUÉS del flip objetivo
                // +1 porque queremos actuar DURANTE el flip N, no después de completarlo
                if (logo_current_flip_count_ + 1 >= logo_target_flip_number_) {
                    // Monitorear progreso del flip actual
                    if (png_shape->isFlipping()) {
                        float flip_progress = png_shape->getFlipProgress();
                        if (flip_progress >= logo_target_flip_percentage_) {
                            should_trigger = true;  // ¡Trigger durante el flip!
                        }
                    }
                }
            }
        } else {
            // CAMINO A: Esperar convergencia + tiempo (comportamiento original)
            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 {
        // DEMO/DEMO_LITE: Timer simple como antes
        should_trigger = demo_timer_ >= demo_next_action_time_;
    }

    // Si es hora de ejecutar acción
    if (should_trigger) {
        // MODO LOGO: Sistema de acciones variadas con gravedad dinámica
        if (current_app_mode_ == AppMode::LOGO) {
            // Llamar a Engine para ejecutar acciones de LOGO
            // TODO FASE 9: Mover lógica de acciones LOGO desde Engine a StateManager
            if (engine_) {
                engine_->performLogoAction(logo_waiting_for_flip_);
            }
        }
        // MODO DEMO/DEMO_LITE: Acciones normales
        else {
            bool is_lite = (current_app_mode_ == AppMode::DEMO_LITE);
            performDemoAction(is_lite);

            // Resetear timer y calcular próximo intervalo aleatorio
            demo_timer_ = 0.0f;

            // Usar intervalos diferentes según modo
            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;

    // Resetear timer al cambiar modo
    demo_timer_ = 0.0f;

    // Configurar timer de demo según el modo
    if (new_mode == AppMode::DEMO || new_mode == AppMode::DEMO_LITE || new_mode == AppMode::LOGO) {
        float min_interval, max_interval;

        if (new_mode == AppMode::LOGO) {
            // Escalar tiempos con resolución (720p como base)
            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);  // Randomizar estado al entrar
    }
}

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);  // Randomizar estado al entrar
    }
}

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

// ===========================================================================
// ACCIONES DE DEMO - Migrado desde Engine::performDemoAction()
// ===========================================================================

void StateManager::performDemoAction(bool is_lite) {
    // ============================================
    // SALTO AUTOMÁTICO A LOGO MODE (Easter Egg)
    // ============================================

    // Obtener información necesaria desde Engine via callbacks
    // (En el futuro, se podría pasar como parámetros al método)
    if (!engine_) return;

    // TODO FASE 9: Eliminar callbacks a Engine y pasar parámetros necesarios

    // Por ahora, delegar las acciones DEMO completas a Engine
    // ya que necesitan acceso a múltiples componentes (SceneManager, ThemeManager, etc.)
    engine_->executeDemoAction(is_lite);
}

// ===========================================================================
// RANDOMIZACIÓN AL INICIAR DEMO - Migrado desde Engine::randomizeOnDemoStart()
// ===========================================================================

void StateManager::randomizeOnDemoStart(bool is_lite) {
    // Delegar a Engine para randomización completa
    // TODO FASE 9: Implementar lógica completa aquí
    if (engine_) {
        engine_->executeRandomizeOnDemoStart(is_lite);
    }
}

// ===========================================================================
// TOGGLE GRAVEDAD (para DEMO) - Migrado desde Engine::toggleGravityOnOff()
// ===========================================================================

void StateManager::toggleGravityOnOff() {
    // Delegar a Engine temporalmente
    if (engine_) {
        engine_->executeToggleGravityOnOff();
    }
}

// ===========================================================================
// ENTRAR AL MODO LOGO - Migrado desde Engine::enterLogoMode()
// ===========================================================================

void StateManager::enterLogoMode(bool from_demo, int current_screen_width, int current_screen_height, size_t ball_count) {
    // Guardar si entrada fue manual (tecla K) o automática (desde DEMO)
    logo_entered_manually_ = !from_demo;

    // Resetear variables de espera de flips
    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);

    // Delegar configuración visual a Engine
    // TODO FASE 9: Mover configuración completa aquí
    if (engine_) {
        engine_->executeEnterLogoMode(ball_count);
    }
}

// ===========================================================================
// SALIR DEL MODO LOGO - Migrado desde Engine::exitLogoMode()
// ===========================================================================

void StateManager::exitLogoMode(bool return_to_demo) {
    if (current_app_mode_ != AppMode::LOGO) return;

    // Resetear flag de entrada manual
    logo_entered_manually_ = false;

    // Delegar restauración visual a Engine
    // TODO FASE 9: Mover lógica completa aquí
    if (engine_) {
        engine_->executeExitLogoMode();
    }

    if (!return_to_demo) {
        // Salida manual (tecla K): volver a SANDBOX
        setState(AppMode::SANDBOX, 0, 0);
    } else {
        // Volver al modo previo (DEMO o DEMO_LITE)
        current_app_mode_ = previous_app_mode_;
    }
}
