#include "infinite_canvas/canvas.h"
#include "infinite_canvas/web_surface.h"

#if defined(INFINITE_CANVAS_DEV_UI)
#include "infinite_canvas/dev_ui.h"
#endif

#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    Dowa_Arena *p_arena;
    Canvas_Camera camera;
    Canvas_Scene scene;
    Canvas_Web_Surface web_surface;
    Font font;
    Canvas_Theme theme;
    boolean owns_font;
    const char *p_screenshot_path;
    uint32 frame_count;
#if defined(INFINITE_CANVAS_DEV_UI)
    Canvas_Dev_UI dev_ui;
#endif
} Canvas_App;

static Canvas_App *g_app = NULL;

static void Canvas_App_Draw_Frame(void)
{
    int32 width = GetScreenWidth();
    int32 height = GetScreenHeight();
    Canvas_Camera_Set_Viewport(&g_app->camera, width, height);

    boolean block_pointer_input = FALSE;
#if defined(INFINITE_CANVAS_DEV_UI)
    block_pointer_input = Canvas_Dev_UI_Contains_Pointer(&g_app->dev_ui);
#endif
    boolean web_input = Canvas_Web_Surface_Update_Input(
        &g_app->web_surface,
        &g_app->camera,
        &g_app->scene);
    block_pointer_input = block_pointer_input || web_input;
    boolean entity_input = Canvas_Scene_Update_Interaction(
        &g_app->scene,
        &g_app->camera,
        block_pointer_input);
    boolean keyboard_focus =
        Canvas_Scene_Is_Text_Editing(&g_app->scene) ||
        Canvas_Web_Surface_Is_Focused(&g_app->web_surface);
    if (!keyboard_focus && IsKeyPressed(KEY_P)) {
        Canvas_Scene_Toggle_Selected_Pin(&g_app->scene, &g_app->camera);
    }
    Canvas_Update_Camera_Input(
        &g_app->camera,
        block_pointer_input || entity_input,
        keyboard_focus);
    Canvas_Scene_Sync_Pinned(&g_app->scene, &g_app->camera);
    Canvas_Scene_Update_Notification_Stack(&g_app->scene, &g_app->camera);

    Canvas_Web_Surface_Sync(&g_app->web_surface, &g_app->camera, &g_app->scene);

    BeginDrawing();
    ClearBackground(g_app->theme.background);
    Canvas_Draw_World(
        &g_app->camera,
        &g_app->scene,
        g_app->font,
        &g_app->theme);
    Canvas_Web_Surface_Draw(&g_app->web_surface, &g_app->camera, &g_app->scene);
#if defined(INFINITE_CANVAS_DEV_UI)
    Canvas_Dev_UI_Draw(
        &g_app->dev_ui,
        &g_app->camera,
        &g_app->scene,
        g_app->font,
        &g_app->theme);
#endif
    EndDrawing();
    g_app->frame_count++;
#if !defined(PLATFORM_WEB)
    if (g_app->frame_count == 30) {
        RestoreWindow();
        SetWindowFocused();
    }
#endif
    if (g_app->p_screenshot_path &&
        g_app->frame_count == 180) {
        TakeScreenshot(g_app->p_screenshot_path);
    }
}

int main(int argc, char **p_argv)
{
#if !defined(PLATFORM_WEB)
    int32 subprocess_result = Canvas_Web_Surface_Execute_Subprocess(argc, p_argv);
    if (subprocess_result >= 0) return subprocess_result;
#else
    (void)argc;
    (void)p_argv;
#endif

    Dowa_Arena *p_arena = Dowa_Arena_Create(8 * ONE_MEGA_BYTE);
    if (!p_arena) return 1;

    g_app = (Canvas_App *)Dowa_Arena_Allocate(p_arena, sizeof(*g_app));
    if (!g_app) {
        Dowa_Arena_Free(p_arena);
        return 1;
    }
    memset(g_app, 0, sizeof(*g_app));
    g_app->p_arena = p_arena;
    g_app->p_screenshot_path = getenv("INFINITE_CANVAS_SCREENSHOT");
    Canvas_Theme_Resolve(
        &g_app->theme,
        Canvas_Theme_Mode_From_String(getenv("INFINITE_CANVAS_THEME")));

    SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT);
#if defined(INFINITE_CANVAS_DEV_UI)
    InitWindow(1920, 1200, "Infinite Canvas");
    SetWindowMinSize(1200, 800);
#else
    InitWindow(1280, 720, "Infinite Canvas");
    SetWindowMinSize(640, 360);
#endif
    SetTargetFPS(60);
#if !defined(PLATFORM_WEB)
    SetWindowFocused();
#endif
    if (!Canvas_Web_Surface_Init(&g_app->web_surface, p_arena)) {
        TraceLog(LOG_WARNING, "Web surface initialization failed");
    }

    g_app->font = LoadFontEx("infinite_canvas/assets/Inter-Variable.ttf", 48, NULL, 0);
    g_app->owns_font = g_app->font.texture.id != 0;
    if (!g_app->owns_font) g_app->font = GetFontDefault();
    else SetTextureFilter(g_app->font.texture, TEXTURE_FILTER_BILINEAR);
    Canvas_Camera_Init(&g_app->camera, GetScreenWidth(), GetScreenHeight());
    Canvas_Scene_Init(&g_app->scene, p_arena);
    if (getenv("INFINITE_CANVAS_BROWSER_STRESS")) {
        Canvas_Scene_Add_Browser_Grid(&g_app->scene);
    } else {
        Canvas_Scene_Add_Demo(&g_app->scene);
    }
    const char *p_image_source = getenv("INFINITE_CANVAS_IMAGE_SOURCE");
    if (p_image_source) {
        for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) {
            Canvas_Entity *p_entity = &g_app->scene.p_entities[index];
            if (p_entity->type == CANVAS_ENTITY_IMAGE) {
                snprintf(p_entity->text, sizeof(p_entity->text), "%s", p_image_source);
                break;
            }
        }
    }
#if !defined(PLATFORM_WEB)
    for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) {
        Canvas_Entity *p_entity = &g_app->scene.p_entities[index];
        if (p_entity->type == CANVAS_ENTITY_WEB_CONTENT) {
            snprintf(p_entity->text, sizeof(p_entity->text), "https://www.google.com");
            break;
        }
    }
#endif
#if defined(INFINITE_CANVAS_DEV_UI)
    Canvas_Dev_UI_Init(&g_app->dev_ui, g_app->font, &g_app->theme);
#endif

#if defined(PLATFORM_WEB)
    emscripten_set_main_loop(Canvas_App_Draw_Frame, 0, 1);
#else
    while (!WindowShouldClose()) Canvas_App_Draw_Frame();
    Canvas_Web_Surface_Shutdown(&g_app->web_surface);
    if (g_app->owns_font) UnloadFont(g_app->font);
    Dowa_Arena_Free(p_arena);
    g_app = NULL;
    CloseWindow();
#endif

    return 0;
}
