#include "Game.h"
#include "Environment.h"
#include <iostream>
#ifdef __ANDROID__
#include <android/log.h>
#endif

#ifdef EMSCRIPTEN
#include <emscripten.h>
#include <emscripten/html5.h>
#endif


// For Emscripten the game is heap-allocated so it can be destroyed and
// re-created when the WebGL context is lost and restored (e.g. fullscreen).
// For Android and Desktop a plain global value is used (no context loss).
#ifdef EMSCRIPTEN
ZL::Game* g_game = nullptr;
//static SDL_Window* win_x = nullptr;
static SDL_GLContext glContext_x; // Не указатель, а сам объект (который суть void*)

#else
ZL::Game game;
#endif


#ifdef EMSCRIPTEN
void MainLoop() {
	g_game->update();
}
#else
void MainLoop() {
    game.update();
}
#endif


#ifdef EMSCRIPTEN

EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
    //delete g_game;
    //g_game = nullptr;
    return EM_TRUE;
}

EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
    //g_game = new ZL::Game();
    //g_game->setup();
    return EM_TRUE;
}

static void applyResize(int logicalW, int logicalH) {
    // Получаем коэффициент плотности пикселей (например, 2.625 на Pixel или 3.0 на Samsung)
    double dpr = emscripten_get_device_pixel_ratio();
    //double dpr = 1; // low quality

    // Вычисляем реальные физические пиксели
    int physicalW = static_cast<int>(logicalW * dpr);
    int physicalH = static_cast<int>(logicalH * dpr);

    // Устанавливаем размер внутреннего буфера канваса
    emscripten_set_canvas_element_size("#canvas", physicalW, physicalH);

    // Сообщаем SDL о новом размере. 
    // ВАЖНО: SDL2 в Emscripten ожидает здесь именно физические пиксели 
    // для корректной работы последующих вызовов glViewport.
    if (ZL::Environment::window) {
        SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH);
    }

    // Пушим событие, чтобы движок пересчитал матрицы проекции
    SDL_Event e = {};
    e.type = SDL_WINDOWEVENT;
    e.window.event = SDL_WINDOWEVENT_RESIZED;
    e.window.data1 = physicalW;
    e.window.data2 = physicalH;
    SDL_PushEvent(&e);

    std::cout << "Resized, new size: " << logicalW << "x" << logicalH 
              << " (physical: " << physicalW << "x" << physicalH 
		<< ", DPR: " << dpr << ")" << std::endl;
}

EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*userData*/) {
    // Use the event's window dimensions — querying the canvas element would
    // return its old fixed size (e.g. 1280x720) before it has been resized.
    applyResize(e->windowInnerWidth, e->windowInnerHeight);
    return EM_FALSE;
}

EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeEvent* e, void* /*userData*/) {
    // Вместо window.innerWidth, попробуйте запросить размер целевого элемента
    // так как после перехода в FS именно он растягивается на весь экран.
    double clientW, clientH;
    emscripten_get_element_css_size("#canvas", &clientW, &clientH);
    applyResize(clientW, clientH);
    return EM_FALSE;
}

int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); // Для WebGL 2.0

    ZL::Environment::window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    glContext_x = SDL_GL_CreateContext(ZL::Environment::window);

    SDL_GL_MakeCurrent(ZL::Environment::window, glContext_x);
	
	g_game = new ZL::Game();
	g_game->setup();
	
	emscripten_set_webglcontextlost_callback("#canvas", nullptr, EM_TRUE, onWebGLContextLost);
        emscripten_set_webglcontextrestored_callback("#canvas", nullptr, EM_TRUE, onWebGLContextRestored);

        // Keep Environment::width/height in sync when the canvas is resized.
        emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onWindowResized);
        emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onFullscreenChanged);
        
        // 2. ИНИЦИАЛИЗАЦИЯ РАЗМЕРОВ: 
        // Получаем реальные размеры окна браузера на момент запуска
        int canvasW = EM_ASM_INT({ return window.innerWidth; });
        int canvasH = EM_ASM_INT({ return window.innerHeight; });

        // Вызываем вашу функцию — она сама применит DPR, выставит физический размер 
        // канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
        applyResize(canvasW, canvasH);
		
	// Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser)
	SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
	// Prevent touch events from generating fake SDL_MOUSEBUTTONDOWN events (mobile browser),
	// since we now handle SDL_FINGERDOWN directly for multi-touch support.
	SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");

    emscripten_set_main_loop(MainLoop, 0, 1);
	
	
    return 0;
}

#endif


#ifdef __ANDROID__

extern "C" int SDL_main(int argc, char* argv[]) {
	// Инициализация SDL перед получением информации о дисплее
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL init failed: %s", SDL_GetError());
        return 1;
    }

    SDL_DisplayMode displayMode;
    if (SDL_GetCurrentDisplayMode(0, &displayMode) != 0) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GetCurrentDisplayMode failed: %s", SDL_GetError());
        SDL_Quit();
        return 1;
    }
    ZL::Environment::width = displayMode.w;
    ZL::Environment::height = displayMode.h;

    __android_log_print(ANDROID_LOG_INFO, "Game", "Display resolution: %dx%d",
                       ZL::Environment::width, ZL::Environment::height);

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);


    ZL::Environment::window = SDL_CreateWindow(
        "Space Ship Game",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        ZL::Environment::width, ZL::Environment::height,
        SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
    );

	if (!ZL::Environment::window) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "Failed to create window: %s", SDL_GetError());
        SDL_Quit();
        return 1;
    }

	SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
    if (!ctx) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError());
        SDL_DestroyWindow(ZL::Environment::window);
        SDL_Quit();
        return 1;
    }

    if (SDL_GL_MakeCurrent(ZL::Environment::window, ctx) != 0) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_MakeCurrent failed: %s", SDL_GetError());
        SDL_GL_DeleteContext(ctx);
        SDL_DestroyWindow(ZL::Environment::window);
        SDL_Quit();
        return 1;
    }

    // Настройка VSync
    if (SDL_GL_SetSwapInterval(1) < 0) {
        __android_log_print(ANDROID_LOG_WARN, "Game", "Unable to set VSync: %s", SDL_GetError());
    }

    // Настройка игры
    try {
        game.setup();
    } catch (const std::exception &e) {
        __android_log_print(ANDROID_LOG_ERROR, "Game", "Game setup failed: %s", e.what());
        return 1;
    }

    while (!game.shouldExit()) {
        game.update();
        SDL_Delay(16);
    }

    return 0;

}


#endif

#ifdef WIN32_LEAN_AND_MEAN

int main(int argc, char *argv[]) {
    try
    {


        constexpr int CONST_WIDTH = 1280;
        constexpr int CONST_HEIGHT = 720;

        ZL::Environment::width = CONST_WIDTH;
        ZL::Environment::height = CONST_HEIGHT;
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
            SDL_Log("SDL init failed: %s", SDL_GetError());
            return 1;
        }

        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

        ZL::Environment::window = SDL_CreateWindow(
            "Space Ship Game",
            SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
            CONST_WIDTH, CONST_HEIGHT,
            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
        );

        SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
        SDL_GL_MakeCurrent(ZL::Environment::window, ctx);

        game.setup();

        while (!game.shouldExit()) {
            game.update();
            SDL_Delay(2);
        }
    }
    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }

    return 0;
}
#endif
