#include "core/rendering/sprite/moving_sprite.hpp"

#include <cmath>  // Para std::abs
#include <utility>

#include "core/rendering/texture.hpp"  // Para Texture

// Constructor
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float horizontal_zoom, float vertical_zoom, SDL_FlipMode flip)
    : Sprite(std::move(texture), pos),
      rotate_(rotate),
      flip_(flip),
      x_(pos.x),
      y_(pos.y),
      horizontal_zoom_(horizontal_zoom),
      vertical_zoom_(vertical_zoom) {}

MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
    : Sprite(std::move(texture), pos),
      flip_(SDL_FLIP_NONE),
      x_(pos.x),
      y_(pos.y),
      horizontal_zoom_(1.0F),
      vertical_zoom_(1.0F) {}

MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
    : Sprite(std::move(texture)),
      flip_(SDL_FLIP_NONE),
      horizontal_zoom_(1.0F),
      vertical_zoom_(1.0F) { Sprite::clear(); }

// Reinicia todas las variables
void MovingSprite::clear() {
    stop();
    Sprite::clear();
}

// Elimina el movimiento del sprite
void MovingSprite::stop() {
    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

    rotate_ = Rotate();  // Inicializa la estructura

    horizontal_zoom_ = 1.0F;  // Zoom aplicado a la anchura
    vertical_zoom_ = 1.0F;    // Zoom aplicado a la altura

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

// Mueve el sprite (time-based)
void MovingSprite::move(float delta_time) {
    // DeltaTime puro: velocidad (pixels/ms) * tiempo (ms)
    x_ += vx_ * delta_time;
    y_ += vy_ * delta_time;

    // Aceleración (pixels/ms²) * tiempo (ms)
    vx_ += ax_ * delta_time;
    vy_ += ay_ * delta_time;

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

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

// Muestra el sprite por pantalla
void MovingSprite::render() {
    getTexture()->render(pos_.x, pos_.y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_);
}

// Establece la rotacion (time-based)
void MovingSprite::rotate(float delta_time) {
    if (rotate_.enabled) {
        rotate_.angle += rotate_.amount * delta_time;
    }
}

// Activa o desactiva el efecto de rotación
void MovingSprite::setRotate(bool enable) {
    rotate_.enabled = enable;
}

// Habilita la rotación y establece el centro en el centro del sprite
void MovingSprite::startRotate() {
    rotate_.enabled = true;
    rotate_.center.x = pos_.w / 2.0F;
    rotate_.center.y = pos_.h / 2.0F;
}

// Detiene la rotación y resetea el ángulo a cero
void MovingSprite::stopRotate(float threshold) {
    if (threshold == 0.0F || std::abs(rotate_.amount) <= threshold) {
        rotate_.enabled = false;
        rotate_.angle = 0.0;
    }
}

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

    pos_ = rect;
}

// Establece el valor de las variables
void MovingSprite::setPos(float pos_x, float pos_y) {
    x_ = pos_x;
    y_ = pos_y;

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

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

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