#include "Bullet.h"
#include "BoneCollisionShape.h"

#include <godot_cpp/classes/engine.hpp>

using namespace godot;

namespace blitz {

static constexpr float BULLET_SPEED = 40.0f;

void Bullet::_bind_methods() {
	ClassDB::bind_method(D_METHOD("_on_timer_timeout"), &Bullet::_on_timer_timeout);
}

Bullet::Bullet() {}

Bullet::~Bullet() {}

void Bullet::_ready() {
	m_Particles = Object::cast_to<GPUParticles3D>(find_child("GPUParticles3D"));
	DEV_ASSERT(m_Particles);
	m_Ray = Object::cast_to<RayCast3D>(find_child("RayCast3D"));
	DEV_ASSERT(m_Ray);
	m_Mesh = Object::cast_to<MeshInstance3D>(find_child("MeshInstance3D"));
	DEV_ASSERT(m_Mesh);
	m_Timer = memnew(Timer);
	add_child(m_Timer);
	m_Timer->connect("timeout", callable_mp(this, &Bullet::_on_timer_timeout));
#if DEBUG_ENABLED
	if (Engine::get_singleton()->is_editor_hint()) {
		return;
	}
#endif
	m_Crosshair = Object::cast_to<Crosshair>(get_parent()->find_child("Crosshair"));
	DEV_ASSERT(m_Crosshair);
}

void Bullet::_physics_process(float a_Delta) {
	Vector3 movement = Vector3(0, 0, -BULLET_SPEED) * a_Delta;
	set_position(get_transform().xform(movement));

	if (m_Ray->is_colliding()) {
		m_Mesh->set_visible(false);
		m_Particles->set_emitting(true);
		m_Ray->set_enabled(false);
		Object* collider = m_Ray->get_collider();

		if (!collider)
			return;

		auto* area_collider = Object::cast_to<BoneCollisionShape>(collider);
		if (!(area_collider && area_collider->is_in_group("enemy")))
			return;

		const StringName& area_name = area_collider->get_name();
		area_collider->call(area_name.match("HeadArea3D") ? "headshot_hit" : "bodyshot_hit");

		m_Timer->set_wait_time(1.0);
		m_Timer->start();
	}
}

void Bullet::_on_timer_timeout() {
	m_Crosshair->set_dot_color(Color(1, 1, 1, 1));
	queue_free();
}

}  // namespace blitz