#include "World.h"
#include "FirstPersonPlayer.h"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

using namespace godot;

namespace blitz {

void World::_bind_methods() {
	ClassDB::bind_method(D_METHOD("_on_first_person_player_hit"), &World::_on_first_person_player_hit);
	ClassDB::bind_method(D_METHOD("_on_timer_timeout"), &World::_on_timer_timeout);
	ClassDB::bind_method(D_METHOD("_on_zombie_spawn_timer_timeout"), &World::_on_zombie_spawn_timer_timeout);
}

World::World() {}
World::~World() {}

void World::_ready() {
	FirstPersonPlayer* player = Object::cast_to<FirstPersonPlayer>(find_child("FirstPersonPlayer"));
	DEV_ASSERT(player);
	if (player) {
		player->connect("a_PlayerHit", callable_mp(this, &World::_on_first_person_player_hit));
	}

	m_RedRect = Object::cast_to<ColorRect>(find_child("HitRect"));
	DEV_ASSERT(m_RedRect);
	m_Timer = memnew(Timer);
	add_child(m_Timer);
	m_Timer->connect("timeout", callable_mp(this, &World::_on_timer_timeout));
	m_ZombieSpawnTimer = memnew(Timer);
	add_child(m_ZombieSpawnTimer);
	m_ZombieSpawnTimer->connect("timeout", callable_mp(this, &World::_on_zombie_spawn_timer_timeout));
	m_Spawns = Object::cast_to<Node3D>(find_child("Spawns"));
	DEV_ASSERT(m_Spawns);
	m_NavigationRegion = Object::cast_to<NavigationRegion3D>(find_child("NavigationRegion3D"));
	DEV_ASSERT(m_NavigationRegion);
	m_ZombieScene = ResourceLoader::get_singleton()->load("res://Scenes/Characters/zombie.tscn");
	if (!m_ZombieScene.is_valid()) {
		ERR_PRINT("Failed to load zombie scene.");
	}
	m_RandomId.instantiate();
	m_RandomId->randomize();
	m_ZombieSpawnTimer->start();
}

void World::_on_first_person_player_hit() {
#if DEBUG_ENABLED
	if (Engine::get_singleton()->is_editor_hint()) {
		return;
	}
#endif
	UtilityFunctions::print("Player hit detected in World.");
	m_RedRect->set_visible(true);
	m_Timer->set_wait_time(0.2);
	m_Timer->start();
}

void World::_on_timer_timeout() {
	m_RedRect->set_visible(false);
}

Node* World::get_random_child(Node* a_ParentNode) {
	m_ZombieSpawnTimer->set_wait_time(4.0);
	if (!a_ParentNode || a_ParentNode->get_child_count() == 0) {
		return nullptr;
	}
	int32_t id = m_RandomId->randi() % a_ParentNode->get_child_count();
	return a_ParentNode->get_child(id);
}

void World::_on_zombie_spawn_timer_timeout() {
#if DEBUG_ENABLED
	if (Engine::get_singleton()->is_editor_hint()) {
		return;
	}
#endif
	auto spawns = Object::cast_to<Node3D>(World::get_random_child(m_Spawns));
	auto spawn_points = spawns->get_global_position();
	m_ZombieInstance = Object::cast_to<Zombie>(m_ZombieScene->instantiate());
	DEV_ASSERT(m_ZombieInstance);
	m_ZombieInstance->set_position(spawn_points);
	m_NavigationRegion->add_child(m_ZombieInstance);
}

}  // namespace blitz