#pragma once

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

#include <vector>  // Para vector

struct Color;

// --- Clase Fade: gestor de transiciones de fundido ---
class Fade {
   public:
    // --- Enums ---
    enum class Type : Uint8 {
        FULLSCREEN = 0,      // Fundido de pantalla completa
        CENTER = 1,          // Fundido desde el centro
        RANDOM_SQUARE = 2,   // Fundido con cuadrados aleatorios
        RANDOM_SQUARE2 = 3,  // Fundido con cuadrados aleatorios (variante 2)
        DIAGONAL = 4,        // Fundido diagonal desde esquina superior izquierda
        VENETIAN = 5,        // Fundido tipo persiana veneciana
    };

    enum class Mode : Uint8 {
        IN = 0,   // Fundido de entrada
        OUT = 1,  // Fundido de salida
    };

    enum class State : Uint8 {
        NOT_ENABLED = 0,  // No activado
        PRE = 1,          // Estado previo
        FADING = 2,       // Fundiendo
        POST = 3,         // Estado posterior
        FINISHED = 4,     // Finalizado
    };

    // --- Constructores y destructor ---
    Fade();
    ~Fade();

    // --- Métodos principales ---
    void reset();                          // Resetea variables para reutilizar el fade
    void render();                         // Dibuja la transición en pantalla
    void update(float delta_time = 0.0F);  // Actualiza el estado interno
    void activate();                       // Activa el fade

    // --- Configuración ---
    void setColor(Uint8 r, Uint8 g, Uint8 b);                                  // Establece el color RGB del fade
    void setColor(Color color);                                                // Establece el color del fade
    void setType(Type type) { type_ = type; }                                  // Establece el tipo de fade
    void setMode(Mode mode) { mode_ = mode; }                                  // Establece el modo de fade
    void setDuration(int milliseconds) { fading_duration_ = milliseconds; }    // Duración del estado FADING en milisegundos
    void setPostDuration(int milliseconds) { post_duration_ = milliseconds; }  // Duración posterior al fade en milisegundos
    void setPreDuration(int milliseconds) { pre_duration_ = milliseconds; }    // Duración previa al fade en milisegundos

    // --- Getters ---
    [[nodiscard]] auto getValue() const -> int { return value_; }
    [[nodiscard]] auto isEnabled() const -> bool { return state_ != State::NOT_ENABLED; }
    [[nodiscard]] auto hasEnded() const -> bool { return state_ == State::FINISHED; }

   private:
    // --- Objetos y punteros ---
    SDL_Renderer* renderer_;   // Renderizador de la ventana
    SDL_Texture* backbuffer_;  // Backbuffer para efectos

    // --- Variables de estado ---
    std::vector<SDL_FRect> square_;     // Vector de cuadrados
    std::vector<int> square_age_;       // Edad de cada cuadrado (para RANDOM_SQUARE2 y DIAGONAL)
    SDL_FRect rect1_, rect2_;           // Rectángulos para efectos
    Type type_;                         // Tipo de fade
    Mode mode_;                         // Modo de fade
    State state_ = State::NOT_ENABLED;  // Estado actual
    Uint8 r_, g_, b_, a_;               // Color del fade (RGBA)
    int num_squares_width_;             // Cuadrados en horizontal
    int num_squares_height_;            // Cuadrados en vertical
    int square_transition_duration_;    // Duración de transición de cada cuadrado en ms
    int fading_duration_{0};            // Duración del estado FADING en milisegundos
    Uint32 fading_start_time_ = 0;      // Tiempo de inicio del estado FADING
    int post_duration_ = 0;             // Duración posterior en milisegundos
    Uint32 post_start_time_ = 0;        // Tiempo de inicio del estado POST
    int pre_duration_ = 0;              // Duración previa en milisegundos
    Uint32 pre_start_time_ = 0;         // Tiempo de inicio del estado PRE
    int value_ = 0;                     // Estado del fade (0-100)

    // --- Inicialización y limpieza ---
    void init();                                               // Inicializa variables
    void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a);  // Limpia el backbuffer con un color RGBA

    // --- Utilidades generales ---
    static auto calculateValue(int min, int max, int current) -> int;  // Calcula el valor del fade entre dos límites

    // --- Lógica de estado ---
    void updatePreState();     // Actualiza el estado previo al fade
    void updateFadingState();  // Actualiza el estado durante el fade
    void updatePostState();    // Actualiza el estado posterior al fade
    void changeToPostState();  // Cambia al estado POST e inicializa el tiempo

    // --- Efectos de fundido (fade) ---
    void updateFullscreenFade();     // Actualiza el fundido de pantalla completa
    void updateCenterFade();         // Actualiza el fundido desde el centro
    void updateRandomSquareFade();   // Actualiza el fundido con cuadrados aleatorios
    void updateRandomSquare2Fade();  // Actualiza el fundido con cuadrados aleatorios (variante 2)
    void updateDiagonalFade();       // Actualiza el fundido diagonal
    void updateVenetianFade();       // Actualiza el fundido tipo persiana veneciana

    // --- Dibujo de efectos visuales ---
    void drawCenterFadeRectangles();                                 // Dibuja los rectángulos del fundido central
    void drawRandomSquares(int active_count);                        // Dibuja los cuadrados aleatorios del fundido
    void drawRandomSquares2();                                       // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2)
    void drawDiagonal();                                             // Dibuja los cuadrados con patrón diagonal
    void activateDiagonal(int diagonal_index, Uint32 current_time);  // Activa una diagonal específica
    void drawVenetianBlinds();                                       // Dibuja las persianas venecianas del fundido
};