#pragma once

#include <SDL3/SDL.h>

#include <cstdint>  // Para uint8_t
#include <memory>   // Para shared_ptr
#include <string>   // Para string
#include <vector>   // Para vector

#include "game/scenes/scene.hpp"  // Para Scene
class Sprite;                     // lines 8-8
class Surface;                    // lines 9-9
class PixelReveal;
class DeltaTimer;

class Ending : public Scene {
   public:
    // --- Constructor y Destructor ---
    Ending();
    ~Ending() override;  // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations

    // --- Bucle principal (SDL3 Callback API) ---
    void iterate() override;
    void handleEvent(const SDL_Event& event) override;

   private:
    // --- Enumeraciones ---
    enum class State : std::uint8_t {
        WARMING_UP,
        SCENE_0,
        SCENE_1,
        SCENE_2,
        SCENE_3,
        SCENE_4,
        ENDING
    };

    // --- Estructuras ---
    struct EndingSurface {
        std::shared_ptr<Surface> image_surface;     // Surface a mostrar
        std::shared_ptr<Sprite> image_sprite;       // SSprite para mostrar la textura
        std::unique_ptr<PixelReveal> pixel_reveal;  // Efecto de revelado pixel a pixel
        int pos_x{0};                               // Posición X de renderizado
        int pos_y{0};                               // Posición Y de renderizado
    };

    struct TextAndPosition {
        std::string caption;  // Texto
        int pos{0};           // Posición
    };

    struct TextIndex {
        int index{0};    // Índice del texto
        int trigger{0};  // Disparador temporal
    };

    struct SceneData {
        std::vector<TextIndex> text_index;  // Índices del vector de textos a mostrar y su disparador
        int picture_index{0};               // Índice del vector de imágenes a mostrar
        int counter_end{0};                 // Valor del contador en el que finaliza la escena
    };

    // --- Constantes de tiempo (basado en 60 FPS) ---
    static constexpr float WARMUP_DURATION = 3.333F;          // 200 frames @ 60fps
    static constexpr float SCENE_0_DURATION = 16.667F;        // 1000 frames @ 60fps
    static constexpr float SCENE_1_DURATION = 23.333F;        // 1400 frames @ 60fps
    static constexpr float SCENE_2_DURATION = 16.667F;        // 1000 frames @ 60fps
    static constexpr float SCENE_3_DURATION = 13.333F;        // 800 frames @ 60fps
    static constexpr float SCENE_4_DURATION = 16.667F;        // 1000 frames @ 60fps
    static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F;    // Filas de texto reveladas por segundo
    static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F;   // Filas de imagen reveladas por segundo
    static constexpr float STEP_DURATION = 2.0F / 60.0F;      // Segundos por paso de revelado (2 frames @ 60fps)
    static constexpr int REVEAL_STEPS = 4;                    // Pasos de revelado por fila
    static constexpr float TEXT_LAPSE = 1.333F;               // 80 frames @ 60fps
    static constexpr float FADEOUT_START_OFFSET = 1.667F;     // Inicio cortinilla 100 frames antes del fin
    static constexpr float COVER_PIXELS_PER_SECOND = 120.0F;  // Filas cubiertas por segundo
    static constexpr int COVER_STEPS = 4;                     // Pasos por fila
    static constexpr float ENDING_DURATION = 2.0F;            // Duración del estado ENDING (2 segundos)
    static constexpr int MUSIC_FADE_DURATION = 1800;          // Fade de audio en milisegundos (1.8 segundos)

    // --- Métodos ---
    void update();                                                    // Actualiza el objeto
    void render();                                                    // Dibuja el final en pantalla
    static void handleInput();                                        // Comprueba las entradas
    void iniTexts();                                                  // Inicializa los textos
    void iniPics();                                                   // Inicializa las imágenes
    void iniScenes();                                                 // Inicializa las escenas
    void updateState(float delta_time);                               // Actualiza la máquina de estados
    void handleSceneFadeout(float scene_duration, float delta_time);  // Lógica de fade común a los estados SCENE_N
    void transitionToState(State new_state);                          // Transición entre estados
    void updateSpriteCovers();                                        // Actualiza las cortinillas de los elementos
    void checkChangeScene();                                          // Comprueba si se ha de cambiar de escena
    void updateMusicVolume() const;                                   // Actualiza el volumen de la música

    // --- Variables miembro ---
    // Objetos y punteros a recursos
    std::unique_ptr<PixelReveal> scene_cover_;  // Cortinilla de salida (negro sobre la escena)
    std::unique_ptr<DeltaTimer> delta_timer_;   // Timer para time-based update
    std::vector<EndingSurface> sprite_texts_;   // Vector con los sprites de texto con su cortinilla
    std::vector<EndingSurface> sprite_pics_;    // Vector con los sprites de imágenes con su cortinilla
    std::vector<SceneData> scenes_;             // Vector con los textos e imágenes de cada escena

    // Variables de estado
    State state_{State::WARMING_UP};  // Estado actual
    float state_time_{0.0F};          // Tiempo acumulado en el estado actual
    float total_time_{0.0F};          // Tiempo total acumulado desde el inicio
    float fadeout_time_{0.0F};        // Tiempo acumulado para la cortinilla de salida
    int current_scene_{0};            // Escena actual (0-4)
};