#pragma once

#include <filesystem>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <fstream>
#include <Redacted3D/engine/world.h>
#include <rewindow/types/window.h>

enum class ENGINE_ERROR_CODE: u8 {
    NO_ERROR = 0,
    ANIM_OUT_OF_BOUNDS = 1,
    TEXTURE_NOT_FOUND = 2,
    SHADER_COMPILATION_ERROR = 3,
    SHADER_LINKING_ERROR = 4,
    INVALID_SHADER_TYPE = 5,
    SHADER_NOT_FOUND = 6,
    MODEL_NOT_FOUND = 7,
    MULTI_TEXTURE_SIZE_EXCEEDS = 8,
    TEXTURE_ERASED_WHILE_IN_USE = 9,
    VERTEX_ARRAY_ERASED_WHILE_IN_USE = 10
};

struct EngineError {
    ENGINE_ERROR_CODE error;
    bool critical;
};

class Engine {
private:
    EngineError error;
public:
    std::string workingDir = std::filesystem::current_path().string();
    ReWindow::RWindow* window;
    World* world;
    void setError(ENGINE_ERROR_CODE code, bool critical);
    EngineError getError();
    bool fullscreen;
    bool debug = false;
    bool useVBO = true;
    u64 tickCount = 0;
    u64 frameCount = 0;
    float nearPlane = 0.001f;
    float frameDelta = 0;
    float farPlane = 100.0f;
    float fov = 75;
    [[nodiscard]] float framerate() const;
    static void takeScreenshot() ;
    void quit() const;
    void quit (ENGINE_ERROR_CODE code) const;
    static float getGLVersion();
    void initGL() const;
    void loadConfig();
    static void init();
    void jglRenderPass();
    void preRender();
    void render();
    static void postRender();
    void renderPass();
    [[noreturn]] void renderLoop();

    Engine() {
        error = {ENGINE_ERROR_CODE::NO_ERROR, false};
    }
};
inline auto* engine = new(Engine);