#include "enemy_car.hpp"
#include "godot_cpp/classes/navigation_agent3d.hpp"
#include "godot_cpp/variant/callable_method_pointer.hpp"
#include "rally_rush_game_mode.hpp"
#include "utils/game_root.hpp"
#include "utils/godot_macros.h"

namespace godot {
void EnemyCar::_bind_methods() {
#define CLASSNAME EnemyCar
    GDSIGNAL("damage");
}

void EnemyCar::_enter_tree() {
    CarPhysics::_enter_tree();
    GDGAMEONLY();
    GameRoot3D *game_root = GameRoot3D::get_singleton();
    this->player = Object::cast_to<CarPlayer>(game_root->get_players()[0]->to_node());
    this->agent = this->get_node<NavigationAgent3D>("NavigationAgent3D");
    RallyRushGameMode *game_mode = Object::cast_to<RallyRushGameMode>(game_root->get_game_mode().ptr());
    game_mode->connect("shield_pickup", callable_mp(this, &EnemyCar::start_fleeing));
    game_mode->connect("end_shield_pickup", callable_mp(this, &EnemyCar::stop_fleeing));
}

void EnemyCar::_process(double delta_time) { GDGAMEONLY();
    --this->next_recalc;
    if(this->next_recalc <= 0)
        this->recalculate_navigation();
    Vector3 const target_direction{this->flee
        ? this->get_global_position() - this->player->get_global_position()
        : this->agent->get_next_path_position() - this->get_global_position()};
    Vector3 const direction{this->get_global_basis().get_column(2)};
    float const ang_dif = target_direction.signed_angle_to(direction.normalized(), this->get_global_basis().get_column(1));
    bool const slow = target_direction.length() < this->brake_distance && this->get_current_speed() > 3.f;

    this->set_target_speed(slow ? this->turn_target_speed : this->max_speed);
    this->set_current_steering(Math::abs(ang_dif) * this->steering_speed);
}

void EnemyCar::damage() {
    this->queue_free();
}

void EnemyCar::start_fleeing() {
    this->flee = true;
}

void EnemyCar::stop_fleeing() {
    this->flee = false;
}

void EnemyCar::recalculate_navigation() {
    this->next_recalc = this->recalc_frame_interval;
    this->agent->set_target_position(this->player->get_global_position() + this->player->get_global_basis().get_column(2) * 4.f);
}
}
