#pragma once

#include "Controllable.hpp"
#include "../../core/geometry/Frustum.hpp"
#include "../../core/geometry/Ray.hpp"

/// Moving perspective camera
class Camera {
public:
    struct options {
        float fov = glm::radians(70.f);
        float near_dist = 0.1;
        float far_dist = 64;
    };

    Camera(const Controllable*, const options&);
    ~Camera();

    void update();
    void setOptions(const options &options) {
        o = options;
        updateProjection();
    }
    void setOrigin(const Controllable* ct) {
        origin = ct;
    }

    inline geometry::Frustum getFrustum() const { return geometry::Frustum(ViewMatrix, ProjectionMatrix); }
    inline geometry::Ray getRay() const { return geometry::Ray(origin->position, origin->getDirection(), o.far_dist); }

    constexpr glm::mat4 getViewMatrix() const { return ViewMatrix; }
    constexpr glm::mat4 getProjectionMatrix() const { return ProjectionMatrix; }
    constexpr float getDepth() const { return o.far_dist; }

private:
    const Controllable* origin;

    glm::mat4 ViewMatrix;
    glm::mat4 ProjectionMatrix;
    void updateProjection();

    options o;
};
