#include "core/rendering/surface_moving_sprite.hpp"

#include <utility>

#include "core/rendering/surface.hpp"  // Para Surface

// Constructor
SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip)
    : SurfaceSprite(std::move(surface), pos),
      x_(pos.x),
      y_(pos.y),
      flip_(flip) { SurfaceSprite::pos_ = pos; }

SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
    : SurfaceSprite(std::move(surface), pos),
      x_(pos.x),
      y_(pos.y),
      flip_(SDL_FLIP_NONE) { SurfaceSprite::pos_ = pos; }

SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface)
    : SurfaceSprite(std::move(surface)),
      x_(0.0F),
      y_(0.0F),
      flip_(SDL_FLIP_NONE) { SurfaceSprite::clear(); }

// Reinicia todas las variables
void SurfaceMovingSprite::clear() {
    x_ = 0.0F;  // Posición en el eje X
    y_ = 0.0F;  // Posición en el eje Y

    vx_ = 0.0F;  // Velocidad en el eje X. Cantidad de pixeles a desplazarse
    vy_ = 0.0F;  // Velocidad en el eje Y. Cantidad de pixeles a desplazarse

    ax_ = 0.0F;  // Aceleración en el eje X. Variación de la velocidad
    ay_ = 0.0F;  // Aceleración en el eje Y. Variación de la velocidad

    flip_ = SDL_FLIP_NONE;  // Establece como se ha de voltear el sprite

    SurfaceSprite::clear();
}

// Mueve el sprite (time-based)
// Nota: vx_, vy_ ahora se interpretan como pixels/segundo
// Nota: ax_, ay_ ahora se interpretan como pixels/segundo²
void SurfaceMovingSprite::move(float delta_time) {
    // Aplica aceleración a velocidad (time-based)
    vx_ += ax_ * delta_time;
    vy_ += ay_ * delta_time;

    // Aplica velocidad a posición (time-based)
    x_ += vx_ * delta_time;
    y_ += vy_ * delta_time;

    // Actualiza posición entera para renderizado
    pos_.x = static_cast<int>(x_);
    pos_.y = static_cast<int>(y_);
}

// Mueve el sprite (frame-based, deprecated)
void SurfaceMovingSprite::move() {
    // Versión antigua: suma directa sin delta_time
    x_ += vx_;
    y_ += vy_;

    vx_ += ax_;
    vy_ += ay_;

    pos_.x = static_cast<int>(x_);
    pos_.y = static_cast<int>(y_);
}

// Actualiza las variables internas del objeto (time-based)
void SurfaceMovingSprite::update(float delta_time) {
    move(delta_time);
}

// Actualiza las variables internas del objeto (frame-based, deprecated)
void SurfaceMovingSprite::update() {
    move();
}

// Muestra el sprite por pantalla
void SurfaceMovingSprite::render() {
    surface_->render(pos_.x, pos_.y, &clip_, flip_);
}

// Muestra el sprite por pantalla
void SurfaceMovingSprite::render(Uint8 source_color, Uint8 target_color) {
    surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_, flip_);
}

// Establece la posición y_ el tamaño del objeto
void SurfaceMovingSprite::setPos(SDL_FRect rect) {
    x_ = rect.x;
    y_ = rect.y;

    pos_ = rect;
}

// Establece el valor de las variables
void SurfaceMovingSprite::setPos(float x, float y) {
    x_ = x;
    y_ = y;

    pos_.x = static_cast<int>(x_);
    pos_.y = static_cast<int>(y_);
}

// Establece el valor de la variable
void SurfaceMovingSprite::setPosX(float value) {
    x_ = value;
    pos_.x = static_cast<int>(x_);
}

// Establece el valor de la variable
void SurfaceMovingSprite::setPosY(float value) {
    y_ = value;
    pos_.y = static_cast<int>(y_);
}