//
// Created by sebastian on 07.02.26.
//

#include "MousePicker.h"

#include "InputManager.h"
#include "../../core/Application.h"
#include "../../toolbox/MathUtils.h"


void MousePicker::update(const Camera& camera) {
    viewMatrix = MathUtils::createViewMatrix(camera);
    currentRay = calculateMouseRay();
}

glm::vec3 MousePicker::calculateMouseRay() {
    glm::vec2 mouseXY = InputManager::getMousePosition();

    glm::vec2 normalizedDeviceCoords = getNormalizedDeviceCoords(mouseXY.x, mouseXY.y);
    glm::vec4 clipCoords = glm::vec4(normalizedDeviceCoords.x, normalizedDeviceCoords.y, -1.0f, 1.0f);
    glm::vec4 eyeCoords = toEyeSpace(clipCoords);
    glm::vec3 worldCoords = toWorldSpace(eyeCoords);
    return glm::normalize(worldCoords);
}

glm::vec2 MousePicker::getNormalizedDeviceCoords(float mouseX, float mouseY) {
    float x = (2.f * mouseX) / static_cast<float>(Application::getInstance().getWindow().GetWidth()) - 1.f;
    float y = 1.f - (2.f * mouseY) / static_cast<float>(Application::getInstance().getWindow().GetHeight());
    return {x, y};
}

glm::vec4 MousePicker::toEyeSpace(const glm::vec4 clipCoords) const {
    glm::mat4 inverseProjectionMatrix = glm::inverse(projectionMatrix);
    glm::vec4 eyeCoords = inverseProjectionMatrix * clipCoords;
    return {eyeCoords.x, eyeCoords.y, -1.0f, 0.0f};
}

glm::vec3 MousePicker::toWorldSpace(glm::vec4 eyeCoords) const {
    glm::mat4 inverseViewMatrix = glm::inverse(viewMatrix);
    glm::vec4 worldCoords = inverseViewMatrix * eyeCoords;
    return {worldCoords.x, worldCoords.y, worldCoords.z};
}
