#include "SpringArmPivot.h"

#include "Player.h"
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/input.hpp>
#include <godot_cpp/classes/input_event_mouse_motion.hpp>
#include <godot_cpp/classes/spring_arm3d.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

static const float NormalFov = 75.0;
static const float RunFov = 90.0;
static const float CameraBlend = 0.05;

namespace blitz {

void SpringArmPivot::_bind_methods() {
	godot::ClassDB::bind_method(godot::D_METHOD("get_dynfov"), &SpringArmPivot::IsFovDynamic);
	godot::ClassDB::bind_method(godot::D_METHOD("set_dynfov", "dynamic_fov"), &SpringArmPivot::SetDynamicFov);
	ADD_PROPERTY(godot::PropertyInfo(godot::Variant::BOOL, "dynamic_fov"), "set_dynfov", "get_dynfov");
}

SpringArmPivot::SpringArmPivot() {}

SpringArmPivot::~SpringArmPivot() {}

void SpringArmPivot::_ready() {
	m_SpringArm = Object::cast_to<godot::SpringArm3D>(get_child(0));
	m_Camera = Object::cast_to<godot::Camera3D>(m_SpringArm->get_child(0));
	DEV_ASSERT(m_SpringArm);
	DEV_ASSERT(m_Camera);
	if (!godot::Engine::get_singleton()->is_editor_hint()) {
		godot::Input::get_singleton()->set_mouse_mode(godot::Input::MOUSE_MODE_CAPTURED);
	}
}

void SpringArmPivot::_unhandled_input(const godot::Ref<godot::InputEvent>& p_event) {
	auto* event = Object::cast_to<godot::InputEventMouseMotion>(p_event.ptr());
	if (event) {
		rotate_y(-event->get_relative().x * 0.005);
		m_SpringArm->rotate_x(-event->get_relative().y * 0.005);

		godot::Vector3 rotationClamped = m_SpringArm->get_rotation();
		rotationClamped.x = godot::UtilityFunctions::clamp(rotationClamped.x, -Math_PI / 4, Math_PI / 4);
		m_SpringArm->set_rotation(rotationClamped);
	}
}

void SpringArmPivot::_physics_process(float delta) {
	if (m_DynamicFOV) {
		auto* parent = Object::cast_to<Player>(get_owner());
		if (parent->is_on_floor()) {
			if (godot::Input::get_singleton()->is_action_pressed("run")) {
				m_Camera->set_fov(godot::UtilityFunctions::lerp(m_Camera->get_fov(), RunFov, CameraBlend));
			} else {
				m_Camera->set_fov(godot::UtilityFunctions::lerp(m_Camera->get_fov(), NormalFov, CameraBlend));
			}
		} else {
			m_Camera->set_fov(godot::UtilityFunctions::lerp(m_Camera->get_fov(), NormalFov, CameraBlend));
		}
	}
}

}  // namespace blitz
