#include <print>
#include <vector>
#include <fstream>
#include <cassert>
#include <cstdint>

#ifdef __EMSCRIPTEN__
#include <GLFW/emscripten_glfw3.h>
#include <emscripten.h>
#else
#include <GLFW/glfw3.h>
#endif

#include "renderer/graphics.h"
#include "renderer/texture_sheet.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

GLFWwindow *window;

int32_t window_width  = 640;
int32_t window_height = 480;

uint64_t t            = 0;
uint64_t accumulator  = 0;
uint64_t dt           = 0;
uint64_t current_time = 0;

sprite_t sprite {
    .origin = {0.5, 0.5},
    .scale = {512, 512},
    .rotation = 0.0,
    .colour = {1.0, 1.0, 1.0, 1.0},
    .alpha = 1.0,
    .window_space = false,
    .maintain_ar = false,
    .texture = "assets/boy.png"
};

int init() {
    if (!glfwInit())
        return -1;

    dt           = glfwGetTimerFrequency() / 60;
    current_time = glfwGetTimerValue();

    std::println("Hello, Sailor!");

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    window = glfwCreateWindow(window_width, window_height, "Hello World", nullptr, nullptr);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    graphics_init(window);

    texture_manager.load("assets/boy.png");

    return 0;
}

bool is_running() {
    return !glfwWindowShouldClose(window);
}

void main_loop(void *data) {
    uint64_t new_time = glfwGetTimerValue();
    uint64_t frame_time = new_time - current_time;
    current_time = new_time;

    accumulator += frame_time;

    glfwPollEvents();

    uint64_t updates = 0;

    while (accumulator >= dt) {
        accumulator -= dt;
        t += dt;
        updates++;
    }
    // std::println("Updates: {}", updates);
    // std::println("frame time: {}", ((double) (frame_time) / (double) glfwGetTimerFrequency()));
    // std::println("fps: {}", 1.0 / ((double) (frame_time) / (double) glfwGetTimerFrequency()));

    begin_frame();

    double f = (t / (double) glfwGetTimerFrequency());

    for (int x = sprite.scale.x / 2; x < window_width; x += sprite.scale.x) {
        submit_sprite({x + 30 * cos(f), 200 + 30 * sin(f)}, sprite);
    }

    end_frame(window);
}

void deinit() {
    graphics_deinit();
    glfwDestroyWindow(window);
    glfwTerminate();
}

int main() {
    init();

#ifdef __EMSCRIPTEN__
    emscripten_set_main_loop_arg(main_loop, nullptr, 0, true);
#else
    while (is_running()) {
        main_loop(nullptr);
    }
#endif

    deinit();

    return 0;
}
