#include "bullet.h"
#include "param.h"  // for param
#include "sprite.h" // for Sprite
#include <memory>   // for std::unique_ptr

// Constantes evaluables en tiempo de compilación
constexpr int BULLET_WIDTH = 12;
constexpr int BULLET_HEIGHT = 12;
constexpr int BULLET_VELY = -3;
constexpr int BULLET_VELX_LEFT = -2;
constexpr int BULLET_VELX_RIGHT = 2;

// Constructor
Bullet::Bullet(int x, int y, BulletType kind_, bool poweredUp, int owner, SDL_Rect *play_area, std::shared_ptr<Texture> texture)
    : pos_x_(x), pos_y_(y), width_(BULLET_WIDTH), height_(BULLET_HEIGHT), vel_x_(0), vel_y_(BULLET_VELY),
      kind_(kind_), owner_(owner), play_area_(play_area)
{
    vel_x_ = (kind_ == BulletType::LEFT) ? BULLET_VELX_LEFT : (kind_ == BulletType::RIGHT) ? BULLET_VELX_RIGHT
                                                                                           : 0;

    auto sprite_offset = poweredUp ? 3 : 0;
    auto kind_index = static_cast<int>(kind_);
    sprite_ = std::make_unique<Sprite>(SDL_Rect{x, y, BULLET_WIDTH, BULLET_HEIGHT}, texture);
    sprite_->setSpriteClip((kind_index + sprite_offset) * width_, 0, sprite_->getWidth(), sprite_->getHeight());

    collider_.r = width_ / 2;
    shiftColliders();
}

// Implementación de render (llama al render del sprite_)
void Bullet::render()
{
    sprite_->render();
}

// Implementación del movimiento usando BulletMoveStatus
BulletMoveStatus Bullet::move()
{
    pos_x_ += vel_x_;
    if (pos_x_ < param.game.play_area.rect.x - width_ || pos_x_ > play_area_->w)
    {
        disable();
        return BulletMoveStatus::OUT;
    }

    pos_y_ += vel_y_;
    if (pos_y_ < param.game.play_area.rect.y - height_)
    {
        disable();
        return BulletMoveStatus::OUT;
    }

    sprite_->setPosX(pos_x_);
    sprite_->setPosY(pos_y_);
    shiftColliders();

    return BulletMoveStatus::OK;
}

bool Bullet::isEnabled() const
{
    return kind_ != BulletType::NULL_TYPE;
}

void Bullet::disable()
{
    kind_ = BulletType::NULL_TYPE;
}

int Bullet::getPosX() const
{
    return pos_x_;
}

int Bullet::getPosY() const
{
    return pos_y_;
}

void Bullet::setPosX(int x)
{
    pos_x_ = x;
}

void Bullet::setPosY(int y)
{
    pos_y_ = y;
}

int Bullet::getVelY() const
{
    return vel_y_;
}

BulletType Bullet::getKind() const
{
    return kind_;
}

int Bullet::getOwner() const
{
    return owner_;
}

Circle &Bullet::getCollider()
{
    return collider_;
}

void Bullet::shiftColliders()
{
    collider_.x = pos_x_ + collider_.r;
    collider_.y = pos_y_ + collider_.r;
}
