#pragma once

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

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

#include "game/options.hpp"  // Para AudioOptions, MusicOptions, audio
#include "utils/color.hpp"   // Para Zone, Color
#include "utils/param.hpp"   // Para Param, ParamGame, param
#include "utils/utils.hpp"

// Declaraciones adelantadas
class BalloonManager;
class Fade;
class Player;
class TiledBG;

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

    // --- 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:
    // --- Métodos del bucle principal ---
    void update(float delta_time);       // Actualización principal de la lógica (time-based)
    auto calculateDeltaTime() -> float;  // Calcula el deltatime
    void initVars();                     // Inicializa variables
    void startCredits();                 // Inicializa mas variables

    // --- Constantes de clase (time-based) ---
    static constexpr int PLAY_AREA_HEIGHT = 200;
    static constexpr float FAST_FORWARD_MULTIPLIER = 6.0F;
    static constexpr float BLACK_RECT_INTERVAL_S = 4.0F / 60.0F;  // ~0.0667s (cada 4 frames a 60fps)
    static constexpr int HORIZONTAL_SPEED = 2;
    static constexpr float MAX_TIME_AFTER_LOGO_S = 20.0F;
    static constexpr float PRE_FADE_DELAY_S = 8.0F;

    // --- Objetos principales ---
    std::unique_ptr<BalloonManager> balloon_manager_;  // Gestión de globos
    std::unique_ptr<TiledBG> tiled_bg_;                // Mosaico animado de fondo
    std::unique_ptr<Fade> fade_in_;                    // Fundido de entrada
    std::unique_ptr<Fade> fade_out_;                   // Fundido de salida
    std::vector<std::shared_ptr<Player>> players_;     // Vector de jugadores

    // --- Gestión de texturas ---
    SDL_Texture* text_texture_;  // Textura con el texto de créditos
    SDL_Texture* canvas_;        // Textura donde se dibuja todo

    // --- Temporización (time-based puro) ---
    Uint64 last_time_ = 0;                     // Último tiempo registrado para deltaTime
    float elapsed_time_balloons_ = 0.0F;       // Tiempo acumulado para lanzamiento de globos (segundos)
    float counter_pre_fade_ = 0.0F;            // Tiempo antes de activar fundido final (segundos)
    float time_since_logo_positioned_ = 0.0F;  // Tiempo desde que el logo llegó a su posición (segundos)
    float current_step_ = 0.0F;
    int total_steps_ = 1;
    bool initialized_ = false;

    // --- Guardar estados iniciales para cálculo de pasos ---
    int init_top_h_ = 0;
    int init_bottom_y_ = 0;
    int init_left_w_ = 0;
    int init_right_x_ = 0;

    // --- Variables de estado ---
    bool fading_ = false;                 // Estado del fade final
    bool want_to_pass_ = false;           // Jugador quiere saltarse créditos
    bool mini_logo_on_position_ = false;  // Minilogo en posición final
    bool vertical_done_ = false;
    bool horizontal_done_ = false;

    // --- Diseño y posicionamiento ---
    float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2;  // Tamaño de las barras negras
    int mini_logo_final_pos_ = 0;                                                   // Posición final del minilogo
    Color color_;                                                                   // Color usado para los efectos

    // --- Control de audio ---
    int initial_volume_ = Options::audio.music.volume;  // Volumen inicial
    int steps_ = 0;                                     // Pasos para reducir audio

    // --- Estado de acumuladores para animaciones ---
    struct CreditsState {
        float texture_accumulator = 0.0F;
        float balloon_accumulator = 0.0F;
        float powerball_accumulator = 0.0F;
        float black_rect_accumulator = 0.0F;
        float r = 255.0F;  // UPPER_LIMIT
        float g = 0.0F;    // LOWER_LIMIT
        float b = 0.0F;    // LOWER_LIMIT
        float step_r = -0.5F;
        float step_g = 0.3F;
        float step_b = 0.1F;
    } credits_state_;

    // --- Rectángulos de renderizado ---
    // Texto de créditos
    SDL_FRect credits_rect_src_ = param.game.game_area.rect;
    SDL_FRect credits_rect_dst_ = param.game.game_area.rect;

    // Mini logo
    SDL_FRect mini_logo_rect_src_ = param.game.game_area.rect;
    SDL_FRect mini_logo_rect_dst_ = param.game.game_area.rect;

    // Definición del área de juego
    SDL_FRect play_area_ = {
        .x = param.game.game_area.rect.x,
        .y = param.game.game_area.rect.y + black_bars_size_,
        .w = param.game.game_area.rect.w,
        .h = PLAY_AREA_HEIGHT};

    // Barras negras para efecto letterbox
    SDL_FRect top_black_rect_ = {
        .x = play_area_.x,
        .y = param.game.game_area.rect.y,
        .w = play_area_.w,
        .h = black_bars_size_};
    SDL_FRect bottom_black_rect_ = {
        .x = play_area_.x,
        .y = param.game.game_area.rect.h - black_bars_size_,
        .w = play_area_.w,
        .h = black_bars_size_};
    SDL_FRect left_black_rect_ = {
        .x = play_area_.x,
        .y = param.game.game_area.center_y - 1,
        .w = 0,
        .h = 2};
    SDL_FRect right_black_rect_ = {
        .x = play_area_.x + play_area_.w,
        .y = param.game.game_area.center_y - 1,
        .w = 0,
        .h = 2};

    // Borde para la ventana
    SDL_FRect border_rect_ = play_area_;  // Delimitador de ventana

    void render();              // Renderizado de la escena
    static void checkEvents();  // Manejo de eventos
    void checkInput();          // Procesamiento de entrada

    // --- Métodos de renderizado ---
    void fillTextTexture();  // Crear textura de texto de créditos
    void fillCanvas();       // Renderizar todos los sprites y fondos
    void renderPlayers();    // Renderiza los jugadores
    void drawBorderRect();   // Renderiza el rectangulo del borde

    // --- Métodos de lógica del juego ---
    void throwBalloons(float delta_time);   // Lanzar globos al escenario (time-based)
    void initPlayers();                     // Inicializar jugadores
    void updateAllFades(float delta_time);  // Actualizar estados de fade (time-based)
    void cycleColors(float delta_time);     // Cambiar colores de fondo
    void updatePlayers(float delta_time);   // Actualza los jugadores (time-based)

    // --- Métodos de interfaz ---
    void updateBlackRects();                       // Actualizar rectángulos negros (letterbox) (frame-based)
    void updateBlackRects(float delta_time);       // Actualizar rectángulos negros (letterbox) (time-based)
    void updateBorderRect();                       // Actualizar rectángulo rojo (borde)
    void updateTextureDstRects();                  // Actualizar destinos de texturas (frame-based)
    void updateTextureDstRects(float delta_time);  // Actualizar destinos de texturas (time-based)

    // --- Métodos de audio ---
    static void setVolume(int amount);  // Establecer volumen
    void resetVolume() const;           // Restablecer volumen
};