#pragma once

#include <SDL3/SDL.h>  // Para SDL_Texture, SDL_Renderer, Uint32, SDL_FPoint, SDL_FRect, Uint64

#include <memory>  // Para unique_ptr, shared_ptr
#include <vector>  // Para vector

class Fade;
class Sprite;
class Text;
class Texture;
class TiledBG;

/*
        Esta clase gestiona un estado del programa. Se encarga de poner en pantalla
        un texto explicativo para entender cómo se juega.

        Además muestra algunos items y explica para qué sirven.

        Utiliza dos texturas de apoyo, una con el texto ya escrito y otra donde se combina
        tanto el texto de la primera textura como los sprites de los items.

        Finalmente, una ventana recorre la textura para dar el efecto de que todo se desplaza
        por la pantalla sobre el mosaico de fondo (gestionado por el correspondiente objeto).
*/

// --- Estructuras ---
struct Line {                   // Almacena información de línea animada
    int y;                      // Coordenada Y de la línea
    float x;                    // Coordenada X inicial (usamos float para mayor precisión en el suavizado)
    int direction;              // Dirección de movimiento: -1 para izquierda, 1 para derecha
    float accumulated_time{0};  // Tiempo acumulado desde que empezó la animación (segundos)
    float delay_time{0};        // Tiempo de retraso antes de comenzar la animación (segundos)
    bool started{false};        // Indica si la línea ha comenzado a moverse

    // Constructor de Line
    Line(int y, float x, int direction, float delay)
        : y(y),
          x(x),
          direction(direction),
          delay_time(delay) {}
};

// Clase Instructions
class Instructions {
   public:
    // --- Constructor y destructor ---
    Instructions();
    ~Instructions();

    // --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS ---
    void iterate();                            // Ejecuta un frame
    void handleEvent(const SDL_Event& event);  // Procesa un evento

    // --- Bucle principal legacy (fallback) ---
    void run();

   private:
    // --- Constantes de tiempo (en segundos) ---
    static constexpr float SPRITE_ANIMATION_CYCLE_S = 36.0F / 60.0F;  // Ciclo de animación sprites (≈0.6s)
    static constexpr float START_DELAY_S = 4.0F;                      // Retraso antes de mover líneas (4s)
    static constexpr float LINE_MOVE_DURATION_S = 1.0F;               // Duración movimiento líneas (1s)
    static constexpr float LINE_START_DELAY_S = 0.005F;               // Retraso entre líneas (5ms = 0.005s)
    static constexpr float SCROLL_SPEED_PPS = 60.0F;                  // Velocidad de scroll (60 pixels por segundo)

    // --- Objetos y punteros ---
    SDL_Renderer* renderer_;   // El renderizador de la ventana
    SDL_Texture* texture_;     // Textura fija con el texto
    SDL_Texture* backbuffer_;  // Textura para usar como backbuffer

    std::vector<std::shared_ptr<Texture>> item_textures_;  // Vector con las texturas de los items
    std::vector<std::unique_ptr<Sprite>> sprites_;         // Vector con los sprites de los items
    std::shared_ptr<Text> text_;                           // Objeto para escribir texto
    std::unique_ptr<TiledBG> tiled_bg_;                    // Objeto para dibujar el mosaico animado de fondo
    std::unique_ptr<Fade> fade_;                           // Objeto para renderizar fades

    // --- Variables ---
    float elapsed_time_ = 0.0F;                 // Tiempo transcurrido (segundos)
    Uint64 last_time_ = 0;                      // Último timestamp para calcular delta-time
    SDL_FRect view_;                            // Vista del backbuffer que se va a mostrar por pantalla
    SDL_FPoint sprite_pos_ = {.x = 0, .y = 0};  // Posición del primer sprite en la lista
    float item_space_ = 2.0;                    // Espacio entre los items en pantalla
    std::vector<Line> lines_;                   // Vector que contiene las líneas animadas en la pantalla
    bool all_lines_off_screen_ = false;         // Indica si todas las líneas han salido de la pantalla
    float start_delay_timer_ = 0.0F;            // Timer para retraso antes de mover líneas (segundos)
    bool start_delay_triggered_ = false;        // Bandera para determinar si el retraso ha comenzado

    // --- Métodos internos ---
    void update(float delta_time);                                                                          // Actualiza las variables
    void render();                                                                                          // Pinta en pantalla
    static void checkEvents();                                                                              // Comprueba los eventos
    static void checkInput();                                                                               // Comprueba las entradas
    void fillTexture();                                                                                     // Rellena la textura de texto
    void fillBackbuffer();                                                                                  // Rellena el backbuffer
    void iniSprites();                                                                                      // Inicializa los sprites de los items
    void updateSprites();                                                                                   // Actualiza los sprites
    static auto initializeLines(int height, float line_delay) -> std::vector<Line>;                         // Inicializa las líneas animadas
    static auto moveLines(std::vector<Line>& lines, int width, float duration, float delta_time) -> bool;   // Mueve las líneas usando delta_time puro
    static void renderLines(SDL_Renderer* renderer, SDL_Texture* texture, const std::vector<Line>& lines);  // Renderiza las líneas
    void updateBackbuffer(float delta_time);                                                                // Gestiona la textura con los gráficos
    auto calculateDeltaTime() -> float;                                                                     // Calcula el tiempo transcurrido desde el último frame
};