#include "bullet.h"

#include <memory>  // Para allocator, unique_ptr, make_unique
#include <string>  // Para char_traits, basic_string, operator+, string

#include "param.h"     // Para Param, ParamGame, param
#include "resource.h"  // Para Resource

// Constructor
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner)
    : sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
      pos_x_(x),
      pos_y_(y),
      bullet_type_(bullet_type),
      owner_(owner) {
    vel_x_ = calculateVelocity(bullet_type_);
    sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));

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

// Calcula la velocidad horizontal de la bala basada en su tipo
auto Bullet::calculateVelocity(BulletType bullet_type) -> float {
    switch (bullet_type) {
        case BulletType::LEFT:
            return VEL_X_LEFT;
        case BulletType::RIGHT:
            return VEL_X_RIGHT;
        default:
            return VEL_X_CENTER;
    }
}

// Construye el string de animación basado en el tipo de bala y si está potenciada
auto Bullet::buildAnimationString(BulletType bullet_type, bool powered) -> std::string {
    std::string animation_string = powered ? "powered_" : "normal_";

    switch (bullet_type) {
        case BulletType::UP:
            animation_string += "up";
            break;
        case BulletType::LEFT:
            animation_string += "left";
            break;
        case BulletType::RIGHT:
            animation_string += "right";
            break;
        default:
            break;
    }

    return animation_string;
}

// Implementación de render (llama al render del sprite_)
void Bullet::render() {
    if (bullet_type_ != BulletType::NONE) {
        sprite_->render();
    }
}

// Actualiza el estado del objeto
auto Bullet::update() -> BulletMoveStatus {
    sprite_->update();
    return move();
}

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

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

    shiftSprite();
    shiftColliders();

    return BulletMoveStatus::OK;
}

auto Bullet::isEnabled() const -> bool {
    return bullet_type_ != BulletType::NONE;
}

void Bullet::disable() {
    bullet_type_ = BulletType::NONE;
}

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

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

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

void Bullet::shiftSprite() {
    sprite_->setX(pos_x_);
    sprite_->setY(pos_y_);
}
