#pragma once

#include <memory>  // Para unique_ptr, shared_ptr

#include "core/rendering/sprite/animated_sprite.hpp"  // Para AnimatedSprite
#include "core/rendering/sprite/smart_sprite.hpp"     // Para SmartSprite
#include "core/rendering/sprite/sprite.hpp"           // Para Sprite

class Texture;

// --- Clase GameLogo: gestor del logo del juego ---
class GameLogo {
   public:
    // --- Constantes ---
    static constexpr float COFFEE_VEL_Y = 0.15F * 1000.0F;                 // Velocidad Y de coffee sprite (pixels/s) - 0.15F * 1000 = 150 pixels/s
    static constexpr float COFFEE_ACCEL_Y = 0.00036F * 1000000.0F;         // Aceleración Y de coffee sprite (pixels/s²) - 0.00036F * 1000000 = 360 pixels/s²
    static constexpr float CRISIS_VEL_Y = -0.15F * 1000.0F;                // Velocidad Y de crisis sprite (pixels/s) - -0.15F * 1000 = -150 pixels/s
    static constexpr float CRISIS_ACCEL_Y = -0.00036F * 1000000.0F;        // Aceleración Y de crisis sprite (pixels/s²) - -0.00036F * 1000000 = -360 pixels/s²
    static constexpr int CRISIS_OFFSET_X = 15;                             // Desplazamiento X de crisis sprite
    static constexpr int DUST_SIZE = 16;                                   // Tamaño de dust sprites
    static constexpr float ZOOM_DECREMENT_PER_S = 0.006F * 1000.0F;        // Decremento de zoom por segundo (0.006F * 1000 = 6.0F per second)
    static constexpr float SHAKE_DELAY_S = 33.34F / 1000.0F;               // Delay de shake en segundos (33.34ms / 1000 = 0.03334s)
    static constexpr float POST_FINISHED_FRAME_TIME_S = 16.67F / 1000.0F;  // Tiempo entre decrementos del counter (16.67ms / 1000 = 0.01667s)

    // --- Constructores y destructor ---
    GameLogo(int x, int y);
    ~GameLogo() = default;

    // --- Métodos principales ---
    void render();                  // Pinta la clase en pantalla
    void update(float delta_time);  // Actualiza la lógica de la clase (time-based)
    void enable();                  // Activa la clase

    // --- Getters ---
    [[nodiscard]] auto hasFinished() const -> bool;  // Indica si ha terminado la animación

   private:
    // --- Enums ---
    enum class Status {
        DISABLED,  // Deshabilitado
        MOVING,    // En movimiento
        SHAKING,   // Temblando
        FINISHED,  // Terminado
    };

    // --- Estructuras privadas ---
    struct Shake {
        int desp = 1;                   // Pixels de desplazamiento para agitar la pantalla en el eje x
        int delay = 2;                  // Retraso entre cada desplazamiento de la pantalla al agitarse (frame-based)
        int length = 8;                 // Cantidad de desplazamientos a realizar
        int remaining = length;         // Cantidad de desplazamientos pendientes a realizar
        int counter = delay;            // Contador para el retraso (frame-based)
        float time_accumulator = 0.0F;  // Acumulador de tiempo para deltaTime
        int origin = 0;                 // Valor inicial de la pantalla para dejarla igual tras el desplazamiento

        Shake() = default;
        Shake(int d, int de, int l, int o)
            : desp(d),
              delay(de),
              length(l),
              remaining(l),
              counter(de),
              origin(o) {}

        void init(int d, int de, int l, int o) {
            desp = d;
            delay = de;
            length = l;
            remaining = l;
            counter = de;
            time_accumulator = 0.0F;
            origin = o;
        }
    };

    // --- Objetos y punteros ---
    std::shared_ptr<Texture> dust_texture_;            // Textura con los graficos del polvo
    std::shared_ptr<Texture> coffee_texture_;          // Textura con los graficos de la palabra "COFFEE"
    std::shared_ptr<Texture> crisis_texture_;          // Textura con los graficos de la palabra "CRISIS"
    std::shared_ptr<Texture> arcade_edition_texture_;  // Textura con los graficos de "Arcade Edition"

    std::unique_ptr<AnimatedSprite> dust_left_sprite_;   // Sprite del polvo (izquierda)
    std::unique_ptr<AnimatedSprite> dust_right_sprite_;  // Sprite del polvo (derecha)
    std::unique_ptr<SmartSprite> coffee_sprite_;         // Sprite de "COFFEE"
    std::unique_ptr<SmartSprite> crisis_sprite_;         // Sprite de "CRISIS"
    std::unique_ptr<Sprite> arcade_edition_sprite_;      // Sprite de "Arcade Edition"

    // --- Variables de estado ---
    Shake shake_;                                               // Efecto de agitación
    Status coffee_crisis_status_ = Status::DISABLED;            // Estado de "COFFEE CRISIS"
    Status arcade_edition_status_ = Status::DISABLED;           // Estado de "ARCADE EDITION"
    float x_;                                                   // Posición X del logo
    float y_;                                                   // Posición Y del logo
    float zoom_ = 1.0F;                                         // Zoom aplicado al texto "ARCADE EDITION"
    float post_finished_delay_s_ = POST_FINISHED_FRAME_TIME_S;  // Retraso final tras animaciones (s)
    float post_finished_timer_ = 0.0F;                          // Timer acumulado para retraso final (s)

    // --- Inicialización ---
    void init();                                               // Inicializa las variables
    [[nodiscard]] auto getInitialVerticalDesp() const -> int;  // Calcula el desplazamiento vertical inicial

    // --- Actualización de estados específicos ---
    void updateCoffeeCrisis(float delta_time);         // Actualiza el estado de "Coffee Crisis" (time-based)
    void updateArcadeEdition(float delta_time);        // Actualiza el estado de "Arcade Edition" (time-based)
    void updatePostFinishedCounter(float delta_time);  // Actualiza el contador tras finalizar una animación (time-based)

    // --- Efectos visuales: movimiento y sacudidas ---
    void handleCoffeeCrisisMoving(float delta_time);                                                        // Maneja el movimiento de "Coffee Crisis" (time-based)
    void handleCoffeeCrisisShaking(float delta_time);                                                       // Maneja la sacudida de "Coffee Crisis" (time-based)
    void handleArcadeEditionMoving(float delta_time);                                                       // Maneja el movimiento de "Arcade Edition" (time-based)
    void handleArcadeEditionShaking(float delta_time);                                                      // Maneja la sacudida de "Arcade Edition" (time-based)
    void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr);          // Procesa el efecto de sacudida en sprites (frame-based)
    void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float delta_time);  // Procesa el efecto de sacudida en sprites (time-based)
    void processArcadeEditionShake(float delta_time);                                                       // Procesa la sacudida específica de "Arcade Edition" (time-based)
    [[nodiscard]] auto calculateShakeDisplacement() const -> int;                                           // Calcula el desplazamiento de la sacudida

    // --- Gestión de finalización de efectos ---
    void handleCoffeeCrisisFinished(float delta_time);  // Maneja el final de la animación "Coffee Crisis" (time-based)
    void finishCoffeeCrisisShaking();                   // Finaliza la sacudida de "Coffee Crisis"
    void finishArcadeEditionMoving();                   // Finaliza el movimiento de "Arcade Edition"

    // --- Utilidades ---
    static void playTitleEffects();            // Reproduce efectos visuales/sonoros del título
    void updateDustSprites(float delta_time);  // Actualiza los sprites de polvo (time-based)
};