#include "colla/colla.h"

#include "libs/handmademath.h"
#include "libs/sokol_gfx.h"

#include "utils.h"

#define WORLD_UP HMM_V3(0, 1, 0)
#define NEAR_Z (0.1f)
#define FAR_Z (1000.f)

typedef struct camera_t camera_t;
struct camera_t {
    HMM_Vec3 pos;
    HMM_Vec3 fwd;
    HMM_Vec3 up;

    float yaw, pitch;

    HMM_Mat4 lookat;
    float speed, mov_speed, look_speed;

    float fov;
};

camera_t cam_init(void) {
    camera_t cam = {
        .fwd = { 0, 0, -1 },
        .up  = { 0, 1, 0 },
        .pos = { 0, 0, 0 },
        .look_speed = 0.3f,
        .mov_speed = 15.f,
        .fov = HMM_DegToRad * 60.f,
    };
    return cam;
}

void cam_update(camera_t *cam, float dt) {
    float strafe  = (float)((int)is_key_down(SAPP_KEYCODE_D) - (int)is_key_down(SAPP_KEYCODE_A));
    float forward = (float)((int)is_key_down(SAPP_KEYCODE_W) - (int)is_key_down(SAPP_KEYCODE_S));
    float movup   = (float)((int)is_key_down(SAPP_KEYCODE_E) - (int)is_key_down(SAPP_KEYCODE_Q));

    float move_speed = cam->mov_speed * dt;
    float look_speed = cam->look_speed * dt;

    HMM_Vec2 delta = mouse_delta();
    cam->yaw   += delta.X * look_speed;
    cam->pitch -= delta.Y * look_speed;
    float max_angle = HMM_DegToRad * 89.f;
    cam->pitch = HMM_Clamp(-max_angle, cam->pitch, max_angle);

    float yc = cosf(cam->yaw);
    float ys = sinf(cam->yaw);
    float pc = cosf(cam->pitch);
    float ps = sinf(cam->pitch);

    cam->fwd = HMM_Norm(HMM_V3(
        pc * ys,
        ps,
        -pc * yc
    ));

    HMM_Vec3 right = HMM_Norm(HMM_Cross(cam->fwd, WORLD_UP));
    cam->up        = HMM_Cross(right, cam->fwd);

    cam->pos = HMM_Add(
        cam->pos,
        HMM_Mul(
            HMM_Add(
                HMM_Add(
                    HMM_Mul(cam->fwd, forward), 
                    HMM_Mul(right, strafe)
                ),
                HMM_Mul(cam->up, movup)
            ), 
            move_speed
        )
    );
    
}

HMM_Mat4 cam_view(camera_t *cam) {
    HMM_Mat4 view = HMM_LookAt_RH(cam->pos, HMM_Add(cam->pos, cam->fwd), cam->up);
    
    return view;
}

HMM_Mat4 cam_proj(camera_t *cam) {
    float aspect = sapp_widthf() / sapp_heightf();
    HMM_Mat4 proj = HMM_Perspective_RH_ZO(cam->fov, aspect, NEAR_Z, FAR_Z);
    return proj;
}

