#include "camera_node.h"
#include "utils/typeclass_helpers.h"
#include "utils/debug.h"

START_REFLECT(CameraNode);
REFLECT_TYPECLASS(CameraNode, Drop);
REFLECT_TYPECLASS(CameraNode, SceneNodeEntity);
END_REFLECT(CameraNode);

impl_Drop_for(CameraNode,
    DestroyCameraNode
)

impl_SceneNodeEntity_defaults(CameraNode);
impl_SceneNodeEntity_for(CameraNode,
    CameraNodeEnterTree,
    CameraNode_default_exit_tree,
    CameraNode_default_tick
)

SceneNode *CreateCameraNode() {
    CameraNode *self = new(CameraNode);
    return CreateSceneNode(CameraNode_as_SceneNodeEntity(self));
}

void DestroyCameraNode(CameraNode *self) {
    SceneNodeDetachEntity(self->node);
    free(self);
}

void CameraNodeEnterTree(CameraNode *self) {
    // register self as main camera if none are selected yet
    if(self->node->scene->main_camera == NULL)
        self->node->scene->main_camera = self;
    // get parent transformable object
    self->transform = TC_CAST(self->node->parent->entity, Transformable);
    ASSERT_RETURN(!tc_is_null(self->transform),, "CameraNodeEnterTree: Camera node HAS TO be the child of a transformable node.");
}

void CameraNodeExitTree(CameraNode *self) {
    // if this is the current main camera, set the main camera to null
    if(self->node->scene->main_camera == self)
        self->node->scene->main_camera = NULL;
}

Camera3D CameraNodeGetCamera(CameraNode *self) {
    // Get the global transform matrix of the parent transformable
    Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
    Matrix mat = TransformGetMatrix(global_transform);
    // get the forward row from the matrix
    Vector3 forward = MATRIX_FORWARD(mat);
    // construct a new camera at the global transform location and facing the forward vector
    return (Camera3D){
        .fovy = 70,
        .position = global_transform.translation,
        .projection = CAMERA_PERSPECTIVE,
        .target = Vector3Add(global_transform.translation, forward),
        .up = MATRIX_UP(mat)
    };
}
