#ifndef BREEZE_GAME_H
#define BREEZE_GAME_H

#include "core/logger.h"

typedef bool (*BzAppInitFunc)(void *);
typedef void (*BzAppUpdateFunc)(float, void *);
typedef void (*BzAppRenderFunc)(float, void *);
typedef void (*BzAppDeinitFunc)(void *);

typedef struct BzAppDesc {
    int32_t    width;
    int32_t    height;
    const char *title;
    int32_t fps;

    BzAppInitFunc   init;
    BzAppUpdateFunc update;
    BzAppRenderFunc render;
    BzAppRenderFunc imguiRender;
    BzAppDeinitFunc deinit;

    void *userData;
} BzAppDesc;

extern bool bzMain(BzAppDesc *appDesc, int argc, const char **argv);

#ifdef BZ_ENTRYPOINT
#include <rlImGui.h>

#ifdef PLATFORM_WEB
#include <emscripten/emscripten.h>
#endif

// https://www.raylib.com/examples/core/loader.html?name=core_custom_logging
static void bzRaylibLogger(int msgType, const char *text, va_list args) {
    BzLoggerLevel level = BZ_LOG_TRACE;
    // translate log
    switch (msgType) {
        case LOG_TRACE:
            level = BZ_LOG_TRACE;
            break;
        case LOG_DEBUG:
            level = BZ_LOG_DEBUG;
            break;
        case LOG_INFO:
            level = BZ_LOG_INFO;
            break;
        case LOG_WARNING:
            level = BZ_LOG_WARNING;
            break;
        case LOG_ERROR:
            level = BZ_LOG_ERROR;
            break;
        case LOG_FATAL:
            level = BZ_LOG_FATAL;
            break;
        default:;
    }

    bzLoggerOnlyLogV(level, text, args);
}

static BzAppDesc appDesc = {0, 0};

static void bzGameLoopTick() {
    float dt = GetFrameTime();
    if (appDesc.update)
        appDesc.update(dt, appDesc.userData);

    //if (ECS)
    //    ecs_progress(ECS, dt);

    BeginDrawing();
    if (appDesc.render)
        appDesc.render(dt, appDesc.userData);

    if (appDesc.imguiRender) {
        rlImGuiBegin();
        appDesc.imguiRender(dt, appDesc.userData);
        rlImGuiEnd();
    }
    EndDrawing();
}


int main(int argc, const char **argv) {
    if (!bzLoggerInit())
        return 1;
    bzLoggerSetLevel(BZ_LOG_INFO);
    bzLogInfo("[Breeze] Logger initialized successfully.");

    SetTraceLogCallback(bzRaylibLogger);

    appDesc = (BzAppDesc){
            1280,
            720,
            "Breeze Engine",
            60
    };

    bool successful = bzMain(&appDesc, argc, argv);
    if (!successful) return 1;

    // Validate
    if (!appDesc.render) {
        bzLogFatal("[Breeze] No render function specifies.");
        return 1;
    }
    bzLogInfo("[Breeze] User initialization (bzMain) successful.");

    InitWindow(appDesc.width, appDesc.height, appDesc.title);
    SetTargetFPS(appDesc.fps);
    // Initialize modules

    if (appDesc.imguiRender)
        rlImGuiSetup(true);

    // User initialize
    if (appDesc.init && !appDesc.init(appDesc.userData)) {
        return 1;
    }

#ifdef PLATFORM_WEB
    emscripten_set_main_loop(bzGameLoopTick, 0, 1);
#else
    while (!WindowShouldClose()) {
        bzGameLoopTick();
    }

    // User deinitialize
    if (appDesc.deinit)
        appDesc.deinit(appDesc.userData);

    // Deinitialize modules
    if (appDesc.imguiRender)
        rlImGuiShutdown();

    CloseWindow();
    bzLoggerDeinit();
#endif

    return 0;
}
#endif

#endif //BREEZE_GAME_H
