#define _USE_MATH_DEFINES
#include "core/rendering/background.hpp"

#include <SDL3/SDL.h>  // Para SDL_FRect, SDL_SetRenderTarget, SDL_CreateTexture, SDL_DestroyTexture, SDL_GetRenderTarget, SDL_RenderTexture, SDL_SetTextureAlphaMod, SDL_SetTextureBlendMode, SDL_BLENDMODE_BLEND, SDL_PixelFormat, SDL_RenderClear, SDL_SetRenderDrawColor, SDL_TextureAccess, SDL_FPoint

#include <algorithm>  // Para clamp, min, max
#include <cmath>      // Para M_PI, cos, sin
#include <string>     // Para basic_string
#include <utility>    // Para move

#include "core/rendering/screen.hpp"                  // Para Screen
#include "core/rendering/sprite/animated_sprite.hpp"  // Para AnimatedSprite
#include "core/rendering/sprite/moving_sprite.hpp"    // Para MovingSprite
#include "core/rendering/sprite/sprite.hpp"           // Para Sprite
#include "core/rendering/texture.hpp"                 // Para Texture
#include "core/resources/resource.hpp"                // Para Resource
#include "utils/param.hpp"                            // Para Param, ParamBackground, param
#include "utils/utils.hpp"                            // Para easeOutCubic

// Constructor
Background::Background(float total_progress_to_complete)
    : renderer_(Screen::get()->getRenderer()),

      buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
      top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
      bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")),
      gradients_texture_(Resource::get()->getTexture("game_sky_colors.png")),
      sun_texture_(Resource::get()->getTexture("game_sun.png")),
      moon_texture_(Resource::get()->getTexture("game_moon.png")),
      grass_sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("game_grass.png"), Resource::get()->getAnimation("game_grass.ani"))),

      total_progress_to_complete_(total_progress_to_complete),
      progress_per_stage_(total_progress_to_complete_ / STAGES),
      sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
      minimum_completed_progress_(total_progress_to_complete_ * MINIMUM_COMPLETED_PROGRESS_PERCENTAGE),

      rect_(SDL_FRect{.x = 0, .y = 0, .w = static_cast<float>(gradients_texture_->getWidth() / 2), .h = static_cast<float>(gradients_texture_->getHeight() / 2)}),
      src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
      dst_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
      attenuate_color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)),

      alpha_color_texture_(param.background.attenuate_color.a),
      previous_alpha_color_texture_(param.background.attenuate_color.a),
      base_(rect_.h) {
    initializePaths();
    initializeRects();
    initializeSprites();
    initializeSpriteProperties();
    initializeTextures();
}

// Destructor
Background::~Background() {
    SDL_DestroyTexture(canvas_);
    SDL_DestroyTexture(color_texture_);
}

// Inicializa las rutas del sol y la luna
void Background::initializePaths() {
    createSunPath();
    createMoonPath();
}

// Inicializa los rectángulos de gradientes y nubes
void Background::initializeRects() {
    gradient_rect_[0] = {.x = 0, .y = 0, .w = rect_.w, .h = rect_.h};
    gradient_rect_[1] = {.x = rect_.w, .y = 0, .w = rect_.w, .h = rect_.h};
    gradient_rect_[2] = {.x = 0, .y = rect_.h, .w = rect_.w, .h = rect_.h};
    gradient_rect_[3] = {.x = rect_.w, .y = rect_.h, .w = rect_.w, .h = rect_.h};

    const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
    const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;

    for (int i = 0; i < 4; ++i) {
        top_clouds_rect_[i] = {.x = 0, .y = i * TOP_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(top_clouds_texture_->getWidth()), .h = TOP_CLOUDS_TEXTURE_HEIGHT};
        bottom_clouds_rect_[i] = {.x = 0, .y = i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(bottom_clouds_texture_->getWidth()), .h = BOTTOM_CLOUDS_TEXTURE_HEIGHT};
    }
}

// Crea los sprites
void Background::initializeSprites() {
    const float TOP_CLOUDS_Y = base_ - 165;
    const float BOTTOM_CLOUDS_Y = base_ - 101;

    top_clouds_sprite_a_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){.x = 0, .y = TOP_CLOUDS_Y, .w = rect_.w, .h = static_cast<float>(top_clouds_texture_->getHeight())});
    top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){.x = rect_.w, .y = TOP_CLOUDS_Y, .w = rect_.w, .h = static_cast<float>(top_clouds_texture_->getHeight())});

    bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){.x = 0, .y = BOTTOM_CLOUDS_Y, .w = rect_.w, .h = static_cast<float>(bottom_clouds_texture_->getHeight())});
    bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){.x = rect_.w, .y = BOTTOM_CLOUDS_Y, .w = rect_.w, .h = static_cast<float>(bottom_clouds_texture_->getHeight())});

    buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
    gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
    sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
    moon_sprite_ = std::make_unique<Sprite>(moon_texture_);
}

// Configura las propiedades iniciales de los sprites
void Background::initializeSpriteProperties() {
    // Velocidades iniciales que coinciden con updateCloudsSpeed() cuando progress=0
    constexpr float INITIAL_TOP_CLOUDS_SPEED_PX_PER_S = 0.05F * 60.0F;            // 3.0 píxeles/segundo (coincide con CLOUDS_INITIAL_SPEED)
    constexpr float INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S = 0.05F * 60.0F / 2.0F;  // 1.5 píxeles/segundo (mitad de velocidad)

    top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
    top_clouds_sprite_a_->setVelX(-INITIAL_TOP_CLOUDS_SPEED_PX_PER_S);

    top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
    top_clouds_sprite_b_->setVelX(-INITIAL_TOP_CLOUDS_SPEED_PX_PER_S);

    bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
    bottom_clouds_sprite_a_->setVelX(-INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S);

    bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
    bottom_clouds_sprite_b_->setVelX(-INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S);

    // grass_sprite_->setY(base_ - grass_sprite_->getHeight());
    // grass_sprite_->resetAnimation();
    grass_sprite_->setPos(0.0F, base_ - 10.0F);
    grass_sprite_->setWidth(320.0F);
    grass_sprite_->setHeight(10.0F);
    // grass_sprite_->setCurrentAnimation(0);

    buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
    sun_sprite_->setPosition(sun_path_.front());
    moon_sprite_->setPosition(moon_path_.front());
}

// Inicializa las texturas de renderizado
void Background::initializeTextures() {
    canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
    SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND);

    color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
    SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
    setColor(attenuate_color_);
    SDL_SetTextureAlphaMod(color_texture_, alpha_color_texture_);
}

// Actualiza la lógica del objeto
void Background::update(float delta_time) {
    // Actualiza la progresión y calcula transiciones
    if (!manual_mode_) {
        updateProgression(delta_time);
    }

    // Actualiza el valor de alpha
    updateAlphaColorTexture(delta_time);

    // Actualiza las nubes
    updateClouds(delta_time);

    // Actualiza el sprite con la hierba
    grass_sprite_->update(delta_time);

    // Calcula el valor de alpha
    alpha_ = std::max((255 - static_cast<int>(255 * transition_)), 0);

    // Mueve el sol y la luna según la progresión
    sun_sprite_->setPosition(sun_path_.at(sun_index_));
    moon_sprite_->setPosition(moon_path_.at(moon_index_));

    // Compone todos los elementos del fondo en la textura
    fillCanvas();
}

// Incrementa la progresión interna
void Background::incrementProgress(float amount) {
    if (state_ == State::NORMAL) {
        float old_progress = progress_;
        progress_ += amount;
        progress_ = std::min(progress_, total_progress_to_complete_);

        // Notifica el cambio si hay callback y el progreso cambió
        if (progress_callback_ && progress_ != old_progress) {
            progress_callback_(progress_);
        }
    }
}

// Establece la progresión absoluta
void Background::setProgress(float absolute_progress) {
    float old_progress = progress_;
    progress_ = std::clamp(absolute_progress, 0.0F, total_progress_to_complete_);

    // Notifica el cambio si hay callback y el progreso cambió
    if (progress_callback_ && progress_ != old_progress) {
        progress_callback_(progress_);
    }
}

// Cambia el estado del fondo
void Background::setState(State new_state) {
    // Si entra en estado completado, inicializar variables de transición
    if (new_state == State::COMPLETED && state_ != State::COMPLETED) {
        completion_initial_progress_ = progress_;
        completion_transition_timer_ = 0.0F;
    }

    state_ = new_state;
}

// Reinicia la progresión
void Background::reset() {
    float old_progress = progress_;
    progress_ = 0.0F;
    state_ = State::NORMAL;
    manual_mode_ = false;
    gradient_number_ = 0;
    transition_ = 0.0F;
    sun_index_ = 0;
    moon_index_ = 0;

    // Resetear variables de transición de completado
    completion_transition_timer_ = 0.0F;
    completion_initial_progress_ = 0.0F;

    // Notifica el cambio si hay callback
    if (progress_callback_ && progress_ != old_progress) {
        progress_callback_(progress_);
    }
}

// Activa/desactiva el modo manual
void Background::setManualMode(bool manual) {
    manual_mode_ = manual;
}

// Establece callback para sincronización automática
void Background::setProgressCallback(ProgressCallback callback) {
    progress_callback_ = std::move(callback);
}

// Elimina el callback
void Background::removeProgressCallback() {
    progress_callback_ = nullptr;
}

// Ajusta la velocidad de las nubes
void Background::setCloudsSpeed(float value) {
    clouds_speed_ = value;

    // En modo manual, aplicar la velocidad directamente
    // Las nubes inferiores van a la mitad de velocidad que las superiores
    top_clouds_sprite_a_->setVelX(value);
    top_clouds_sprite_b_->setVelX(value);
    bottom_clouds_sprite_a_->setVelX(value / 2.0F);
    bottom_clouds_sprite_b_->setVelX(value / 2.0F);
}

// Establece el degradado de fondo
void Background::setGradientNumber(int value) {
    gradient_number_ = value % STAGES;
}

// Ajusta la transición entre texturas
void Background::setTransition(float value) {
    transition_ = std::clamp(value, 0.0F, 1.0F);
}

// Establece la posición del sol
void Background::setSunProgression(float progress) {
    progress = std::clamp(progress, 0.0F, 1.0F);
    sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}

// Establece la posición de la luna
void Background::setMoonProgression(float progress) {
    progress = std::clamp(progress, 0.0F, 1.0F);
    moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}

// Actualiza la progresión y calcula las transiciones
void Background::updateProgression(float delta_time) {
    // Si el juego está completado, hacer transición suave con easing
    if (state_ == State::COMPLETED) {
        completion_transition_timer_ += delta_time;

        // Calcular progreso normalizado de la transición (0.0 a 1.0)
        float t = std::min(completion_transition_timer_ / COMPLETION_TRANSITION_DURATION_S, 1.0F);

        if (t < 1.0F) {
            // Usar easeOutCubic para transición suave (rápido al inicio, lento al final)
            float eased_t = easeOutCubic(static_cast<double>(t));

            // Interpolación desde progreso inicial hasta mínimo
            float progress_range = completion_initial_progress_ - minimum_completed_progress_;
            progress_ = completion_initial_progress_ - (progress_range * eased_t);
        } else {
            // Transición completada, fijar al valor mínimo
            progress_ = minimum_completed_progress_;
        }
    }

    // Calcula la transición de los diferentes fondos
    const float GRADIENT_NUMBER_FLOAT = std::min(progress_ / progress_per_stage_, 3.0F);
    const float PERCENT = GRADIENT_NUMBER_FLOAT - static_cast<int>(GRADIENT_NUMBER_FLOAT);

    gradient_number_ = static_cast<size_t>(GRADIENT_NUMBER_FLOAT);
    transition_ = PERCENT;

    // Calcula la posición del sol
    const float SUN_PROGRESSION = std::min(progress_ / sun_completion_progress_, 1.0F);
    sun_index_ = static_cast<size_t>(SUN_PROGRESSION * (sun_path_.size() - 1));

    // Calcula la posición de la luna
    const float MOON_PROGRESSION = std::min(progress_ / total_progress_to_complete_, 1.0F);
    moon_index_ = static_cast<size_t>(MOON_PROGRESSION * (moon_path_.size() - 1));

    // Actualiza la velocidad de las nubes
    updateCloudsSpeed();
}

// Actualiza la velocidad de las nubes según el estado y progresión
void Background::updateCloudsSpeed() {
    // Cálculo de velocidad según progreso (convertido de frame-based a time-based)
    constexpr float CLOUDS_INITIAL_SPEED_PX_PER_S = 0.05F * 60.0F;                                                    // 3.0 píxeles/segundo (era 0.05 px/frame @ 60fps)
    constexpr float CLOUDS_TOTAL_SPEED_PX_PER_S = 2.00F * 60.0F;                                                      // 120.0 píxeles/segundo (era 2.00 px/frame @ 60fps)
    constexpr float CLOUDS_FINAL_SPEED_RANGE_PX_PER_S = CLOUDS_TOTAL_SPEED_PX_PER_S - CLOUDS_INITIAL_SPEED_PX_PER_S;  // 117.0 píxeles/segundo

    // Velocidad base según progreso (de -3.0 a -120.0 píxeles/segundo, igual que la versión original)
    float base_clouds_speed = (-CLOUDS_INITIAL_SPEED_PX_PER_S) +
        (-CLOUDS_FINAL_SPEED_RANGE_PX_PER_S * (progress_ / total_progress_to_complete_));

    // En estado completado, las nubes se ralentizan gradualmente
    if (state_ == State::COMPLETED) {
        float completion_factor = (progress_ - minimum_completed_progress_) /
            (total_progress_to_complete_ - minimum_completed_progress_);
        completion_factor = std::max(0.1F, completion_factor);
        base_clouds_speed *= completion_factor;
    }

    // Aplicar velocidades diferentes para nubes superiores e inferiores
    const float TOP_CLOUDS_SPEED = base_clouds_speed;
    const float BOTTOM_CLOUDS_SPEED = base_clouds_speed / 2.0F;

    // Aplicar las velocidades a los sprites correspondientes
    top_clouds_sprite_a_->setVelX(TOP_CLOUDS_SPEED);
    top_clouds_sprite_b_->setVelX(TOP_CLOUDS_SPEED);
    bottom_clouds_sprite_a_->setVelX(BOTTOM_CLOUDS_SPEED);
    bottom_clouds_sprite_b_->setVelX(BOTTOM_CLOUDS_SPEED);

    // Guardar la velocidad principal
    clouds_speed_ = TOP_CLOUDS_SPEED;
}

// Actualiza las nubes
void Background::updateClouds(float delta_time) {
    // Mueve las nubes
    top_clouds_sprite_a_->update(delta_time);
    top_clouds_sprite_b_->update(delta_time);
    bottom_clouds_sprite_a_->update(delta_time);
    bottom_clouds_sprite_b_->update(delta_time);

    // Calcula el offset de las nubes
    if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {
        top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
    }

    if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) {
        top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
    }

    if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) {
        bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
    }

    if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) {
        bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
    }
}

// Dibuja el gradiente de fondo
void Background::renderGradient() {
    // Dibuja el gradiente de detras
    gradients_texture_->setAlpha(255);
    gradient_sprite_->setSpriteClip(gradient_rect_[(gradient_number_ + 1) % 4]);
    gradient_sprite_->render();

    // Dibuja el gradiente de delante con una opacidad cada vez menor
    gradients_texture_->setAlpha(alpha_);
    gradient_sprite_->setSpriteClip(gradient_rect_[gradient_number_]);
    gradient_sprite_->render();
}

// Dibuja las nubes de arriba
void Background::renderTopClouds() {
    // Dibuja el primer conjunto de nubes, las de detras
    top_clouds_texture_->setAlpha(255);
    top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
    top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
    top_clouds_sprite_a_->render();
    top_clouds_sprite_b_->render();

    // Dibuja el segundo conjunto de nubes, las de delante
    top_clouds_texture_->setAlpha(alpha_);
    top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[gradient_number_]);
    top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[gradient_number_]);
    top_clouds_sprite_a_->render();
    top_clouds_sprite_b_->render();
}

// Dibuja las nubes de abajo
void Background::renderBottomClouds() {
    // Dibuja el primer conjunto de nubes, las de detras
    bottom_clouds_texture_->setAlpha(255);
    bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
    bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
    bottom_clouds_sprite_a_->render();
    bottom_clouds_sprite_b_->render();

    // Dibuja el segundo conjunto de nubes, las de delante
    bottom_clouds_texture_->setAlpha(alpha_);
    bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
    bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
    bottom_clouds_sprite_a_->render();
    bottom_clouds_sprite_b_->render();
}

// Compone todos los elementos del fondo en la textura
void Background::fillCanvas() {
    // Cambia el destino del renderizador
    auto* temp = SDL_GetRenderTarget(renderer_);
    SDL_SetRenderTarget(renderer_, canvas_);

    // Dibuja el gradiente de fondo
    renderGradient();

    // Dibuja los astros
    sun_sprite_->render();
    moon_sprite_->render();

    // Dibuja las nubes de arriba
    renderTopClouds();

    // Dibuja las nubes de abajo
    renderBottomClouds();

    // Dibuja los edificios
    buildings_sprite_->render();

    // Dibuja la hierba
    grass_sprite_->render();

    // Deja el renderizador apuntando donde estaba
    SDL_SetRenderTarget(renderer_, temp);
}

// Dibuja el objeto
void Background::render() {
    // Fondo
    SDL_RenderTexture(renderer_, canvas_, &src_rect_, &dst_rect_);

    // Atenuación
    SDL_RenderTexture(renderer_, color_texture_, &src_rect_, &dst_rect_);
}

// Establece la posición del objeto
void Background::setPos(SDL_FRect pos) {
    dst_rect_ = pos;

    // Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen
    src_rect_.x = 0;
    src_rect_.y = rect_.h - pos.h;
    src_rect_.w = pos.w;
    src_rect_.h = pos.h;
}

// Establece el color de atenuación
void Background::setColor(Color color) {
    attenuate_color_ = color;

    // Colorea la textura
    auto* temp = SDL_GetRenderTarget(renderer_);
    SDL_SetRenderTarget(renderer_, color_texture_);

    SDL_SetRenderDrawColor(renderer_, attenuate_color_.r, attenuate_color_.g, attenuate_color_.b, 255);
    SDL_RenderClear(renderer_);

    SDL_SetRenderTarget(renderer_, temp);
}

// Establece la transparencia de la atenuación
void Background::setAlpha(int alpha) {
    // Evita que se asignen valores fuera de rango
    alpha = std::clamp(alpha, 0, 255);

    // Guarda el valor actual y establece el nuevo valor
    previous_alpha_color_texture_ = alpha_color_texture_;
    alpha_color_texture_ = alpha;
}

// Actualiza el valor de alpha (time-based)
void Background::updateAlphaColorTexture(float delta_time) {
    // 1. Si ya hemos llegado al destino, no hacemos nada.
    if (alpha_color_texture_ == previous_alpha_color_texture_) {
        return;
    }

    // 2. Define la velocidad del cambio (p. ej., 150 unidades de alfa por segundo).
    //    Puedes ajustar este valor para que la transición sea más rápida o lenta.
    constexpr float ALPHA_TRANSITION_SPEED = 150.0F;

    // 3. Determina la dirección del cambio (subir o bajar el alfa)
    if (alpha_color_texture_ > previous_alpha_color_texture_) {
        // Aumentar el alfa
        current_alpha_float_ += ALPHA_TRANSITION_SPEED * delta_time;
        // Nos aseguramos de no pasarnos del objetivo
        current_alpha_float_ = std::min(current_alpha_float_, static_cast<float>(alpha_color_texture_));
    } else {
        // Disminuir el alfa
        current_alpha_float_ -= ALPHA_TRANSITION_SPEED * delta_time;
        // Nos aseguramos de no quedarnos cortos del objetivo
        current_alpha_float_ = std::max(current_alpha_float_, static_cast<float>(alpha_color_texture_));
    }

    // 4. Actualiza el valor entero solo si ha cambiado lo suficiente
    //    Usamos std::round para un redondeo más natural.
    const auto NEW_ALPHA = static_cast<size_t>(std::round(current_alpha_float_));

    if (NEW_ALPHA != previous_alpha_color_texture_) {
        previous_alpha_color_texture_ = NEW_ALPHA;
        // SDL espera un Uint8 (0-255), así que hacemos un cast seguro.
        SDL_SetTextureAlphaMod(color_texture_, static_cast<Uint8>(previous_alpha_color_texture_));
    }
}

// Precalcula el vector con el recorrido del sol
void Background::createSunPath() {
    constexpr float CENTER_X = 170;
    const float CENTER_Y = base_ - 80;
    constexpr float RADIUS = 120;

    // Generar puntos de la curva desde 90 a 180 grados
    constexpr double STEP = 0.01;
    const int NUM_STEPS = static_cast<int>((M_PI - M_PI / 2) / STEP) + 1;

    for (int i = 0; i < NUM_STEPS; ++i) {
        double theta = M_PI / 2 + (i * STEP);
        float x = CENTER_X + (RADIUS * cos(theta));
        float y = CENTER_Y - (RADIUS * sin(theta));
        sun_path_.push_back({.x = x, .y = y});
    }

    // Agregar puntos en línea recta después de la curva
    constexpr int EXTRA_PIXELS = 40;
    SDL_FPoint last_point = sun_path_.back();
    for (int i = 1; i <= EXTRA_PIXELS; ++i) {
        sun_path_.push_back({.x = last_point.x, .y = last_point.y + i});
    }
}

// Precalcula el vector con el recorrido de la luna
void Background::createMoonPath() {
    constexpr float CENTER_X = 100;
    const float CENTER_Y = base_ - 50;
    constexpr float RADIUS = 140;

    constexpr double STEP = 0.01;
    const int NUM_STEPS = static_cast<int>((M_PI / 2) / STEP) + 1;

    constexpr float FREEZE_PERCENTAGE = 0.2F;  // Porcentaje final del recorrido que se mantiene fijo

    const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0F - FREEZE_PERCENTAGE));

    for (int i = 0; i < NUM_STEPS; ++i) {
        double theta = i * STEP;
        float x = CENTER_X + (RADIUS * cos(theta));
        float y = CENTER_Y - (RADIUS * sin(theta));

        if (i >= FREEZE_START_INDEX && !moon_path_.empty()) {
            moon_path_.push_back(moon_path_.back());  // Repite el último punto válido
        } else {
            moon_path_.push_back({.x = x, .y = y});
        }
    }
}
