//
// Created by sebastian on 29.07.26.
//

#include "Camera.h"

#include <format>
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
glm::vec3 engine::Camera::getForward() const {
    // Yaw um Y-Achse, Pitch um lokale X-Achse — Standard-FPS-Konvention
    glm::vec3 forward;
    forward.x = std::cos(glm::radians(m_pitch)) * std::sin(glm::radians(m_yaw));
    forward.y = std::sin(glm::radians(m_pitch));
    forward.z = -std::cos(glm::radians(m_pitch)) * std::cos(glm::radians(m_yaw));
    return glm::normalize(forward);
}

glm::vec3 engine::Camera::getRight() const {
    return glm::normalize(glm::cross(getForward(), glm::vec3(0.0f, 1.0f, 0.0f)));
}

glm::vec3 engine::Camera::getUp() const {
    return glm::normalize(glm::cross(getRight(), getForward()));
}

void engine::Camera::moveRelative(const glm::vec3 &direction, float speed, float deltaTime) {
    glm::vec3 worldOffset = getRight() * direction.x + getUp() * direction.y + getForward() * direction.z;

    if (worldOffset != glm::vec3(0.0f)) {
        worldOffset = glm::normalize(worldOffset);
    }
    m_position += worldOffset * speed * deltaTime;
}

void engine::Camera::moveWorld(const glm::vec3 &offset) {
    m_position += offset;
}

glm::mat4 engine::Camera::getViewMatrix() const {
    glm::vec3 forward = getForward();
    glm::vec3 up = getUp();

    glm::mat4 view = glm::lookAt(m_position, m_position + forward, up);

    // Roll: Rotation um die Blickachse, nachträglich im View-Space angewendet
    if (m_roll != 0.0f) {
        view = glm::rotate(glm::mat4(1.0f), glm::radians(m_roll), glm::vec3(0.0f, 0.0f, 1.0f)) * view;
    }

    return view;
}

glm::mat4 engine::Camera::getProjectionMatrix() const {
    return glm::perspective(m_fovY, m_aspect, m_near, m_far);
}
