#include <iostream>

#include "client/input/Controller.h"
#include "client/rendering/Engine.h"
#include "client/rendering/Framebuffers.h"
#include "client/rendering/RenderSettings.h"
#include "client/rendering/Shaders.h"
#include "gaming-core/rendering/Window.h"
#include "gaming-core/rendering/WindowOptions.h"
#include "gaming-core/utils/Clock.h"
#include "gaming-core/wrapper/GL.h"
#include "gaming-core/wrapper/GLEW.h"
#include "gaming-core/wrapper/GLFW.h"

#include <memory>
#include <vector>

void updateSize(const Window& window, Size& size, Framebuffers& framebuffers) {
    Size newSize = window.getSize();
    if(newSize.width != size.width || newSize.height != size.height) {
        size = newSize;
        GL::setViewport(size.width, size.height);
        framebuffers.resize(size);
    }
}

int main() {
    if(GLFW::init()) {
        return 0;
    }

    Size size(1024, 620);
    WindowOptions options(4, 0, size, false, "test");
    Window window(options);
    if(window.hasError() || GLEW::init()) {
        return 0;
    }

    Shaders shaders;
    if(shaders.hasError()) {
        return 0;
    }

    Framebuffers framebuffers;
    if(framebuffers.init(size)) {
        return 0;
    }

    RenderSettings renderSettings;
    Engine engine(shaders, framebuffers, size, renderSettings);

    Buttons buttons(window);
    Controller controller(buttons);
    Clock fps;
    Clock tps;
    Game game(controller, fps, tps, renderSettings, size);

    window.show();

    GL::printError("setup error");

    const Clock::Nanos nanosPerTick = 50000000;
    Clock::Nanos lag = 0;
    while(!window.shouldClose() && game.isRunning()) {
        GL::printError("loop error");
        updateSize(window, size, framebuffers);
        engine.renderTick(static_cast<float>(lag) / nanosPerTick, game);
        window.swapBuffers();
        lag += fps.update();
        while(lag >= nanosPerTick) {
            lag -= nanosPerTick;
            tps.update();
            buttons.tick();
            game.tick();
        }
        glfwPollEvents();
    }
    return 0;
}