/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "Input/InputManager.hpp"
#include "SceneIntersectionTestController.hpp"
#include "Scene.hpp"
#include "SimpleDrawable.hpp"
#include "Prefabs/LabelDrawable.hpp"

namespace OpenVulkano::Scene
{
	void SceneIntersectionTestController::Tick()
	{
		Input::InputManager* input = Input::InputManager::GetInstance();
		if (input->GetButtonDown(m_actionClick))
		{
			const float x = input->GetAxis(m_actionClickX);
			const float y = input->GetAxis(m_actionClickY);
			const Ray ray = m_camera->CastRay(Math::Vector2i(x, y));
			const auto& camPos = m_camera->GetPosition();
			const auto scene = m_camera->GetScene();
			std::optional<DrawableRayHit> res;
			for (Drawable* d : scene->rayHittableDrawables)
			{
				for (Node* n : d->GetNodes())
				{
					const auto& m = n->GetWorldMatrix();
					const Math::Vector3f rayLocalDir = normalize(inverse(m) * Math::Vector4f(ray.GetDir(), 0));
					const Math::Vector4f rayLocalPos = inverse(m) * camPos;
					const Ray ray(rayLocalPos, rayLocalDir);
					if (auto hit = d->Intersect(ray))
					{
						// choose the closest one
						if (!res || (hit->distance2 < res->distance2))
						{
							res = hit;
							res->drawable = d;
							res->node = n;
						}
					}
				}
			}

			if (res)
			{
				OnHit.NotifyAll(*res);
			}
		}
	}

	void SceneIntersectionTestController::SetDefaultKeybindings()
	{
		auto input = Input::InputManager::GetInstance();
		m_actionClick = input->GetAction("ClickIntersection");
		m_actionClick->BindKey(Input::InputKey::Mouse::BUTTON_1);
		m_actionClick->BindKey(Input::InputKey::Touch::BUTTON_TAP);

		m_actionClickX = input->GetAction("ClickIntersectionPosX");
		m_actionClickX->BindKey(Input::InputKey::Touch::Axis::AXIS_TAP_X_ABS);
		m_actionClickX->BindKey(Input::InputKey::Mouse::Axis::AXIS_X_ABS);
		m_actionClickY = input->GetAction("ClickIntersectionPosY");
		m_actionClickY->BindKey(Input::InputKey::Touch::Axis::AXIS_TAP_Y_ABS);
		m_actionClickY->BindKey(Input::InputKey::Mouse::Axis::AXIS_Y_ABS);
	}
}
