//
// Created by slinky on 5/3/26.
//

#include "Camera.h"

#include "glm/ext/matrix_transform.hpp"
#include "glm/ext/matrix_clip_space.hpp"

Camera::Camera(const glm::vec3 &pos, float pitch, float yaw, float aspectRatio) : _position(pos), _yaw(yaw), _pitch(pitch), _aspectRatio(aspectRatio) {
    update_camera_vectors();
    update_view();
    update_projection();
}

const glm::mat4& Camera::view() const {
    return _view;
}

const glm::mat4& Camera::projection() const {
    return _projection;
}

const glm::vec3& Camera::position() const {
    return _position;
}

glm::vec3 Camera::front() const {
    return glm::normalize(_front);
}

glm::vec3 Camera::right() const {
    return glm::normalize(_right);
}

glm::vec3 Camera::up() const {
    return glm::normalize(_up);
}

float Camera::aspect_ratio() const {
    return _aspectRatio;
}

void Camera::rotate_pitch(float offset) {
    _pitch += offset;

    if (_pitch < MIN_PITCH) {
        _pitch = MIN_PITCH;
    }

    if (_pitch > MAX_PITCH) {
        _pitch = MAX_PITCH;
    }

    update_camera_vectors();
    update_view();
}

void Camera::rotate_yaw(float offset) {
    _yaw += offset;
    update_camera_vectors();
    update_view();
}

void Camera::translate(const glm::vec3& translation) {
    _position += translation;
    update_view();
}

void Camera::update_aspect_ratio(float aspectRatio) {
    _aspectRatio = aspectRatio;
    _projection = glm::perspective(glm::radians(75.f), _aspectRatio, 0.1f, 100.0f);
}

void Camera::update_camera_vectors() {
    _front = {};
    _front.x = cos(glm::radians(_yaw)) * cos(glm::radians(_pitch));
    _front.y = sin(glm::radians(_pitch));
    _front.z = sin(glm::radians(_yaw)) * cos(glm::radians(_pitch));

    _front = glm::normalize(_front);

    _right = glm::normalize(glm::cross(_front, WORLD_UP));
    _up = glm::normalize(glm::cross(_right, _front));
}

void Camera::update_projection() {
    _projection = glm::perspective(glm::radians(75.f), _aspectRatio, 0.1f, 100.0f);
}

void Camera::update_view() {
    _view = glm::lookAt(_position, _position + _front, _up);
}