/**
 * @file game.cpp
 * @brief Main game implementation
 */

#include "game.hpp"
#include "systems.hpp"
#include "components.hpp"
#include "pipeline.hpp"

#include <cstdio>

bool game_init(GameContext& ctx, const WindowConfig& config) {
    // Initialize SDL3
    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
        SDL_Log("Failed to initialize SDL: %s", SDL_GetError());
        return false;
    }

    // Create window
    ctx.window = SDL_CreateWindow(
        config.title,
        config.width,
        config.height,
        config.flags
    );

    if (!ctx.window) {
        SDL_Log("Failed to create window: %s", SDL_GetError());
        game_shutdown(ctx);
        return false;
    }

    ctx.window_width = config.width;
    ctx.window_height = config.height;

    // Create renderer
    ctx.renderer = SDL_CreateRenderer(ctx.window, nullptr);
    if (!ctx.renderer) {
        SDL_Log("Failed to create renderer: %s", SDL_GetError());
        game_shutdown(ctx);
        return false;
    }

    // Enable VSync
    SDL_SetRenderVSync(ctx.renderer, 1);

    // Register components and systems
    register_systems(ctx.ecs, &ctx);

    // Initialize timing
    ctx.last_time = SDL_GetPerformanceCounter();
    ctx.delta_time = 0.0f;

    // Set running state
    ctx.running = true;
    ctx.paused = false;

    SDL_Log("Game initialized successfully");
    return true;
}

void game_shutdown(GameContext& ctx) {
    if (ctx.renderer) {
        SDL_DestroyRenderer(ctx.renderer);
        ctx.renderer = nullptr;
    }

    if (ctx.window) {
        SDL_DestroyWindow(ctx.window);
        ctx.window = nullptr;
    }

    SDL_Quit();
    SDL_Log("Game shutdown complete");
}

void game_process_events(GameContext& ctx) {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        // Forward events to pipeline visualization (skip while paused to avoid queuing)
        if (ctx.pipeline && !ctx.paused) {
            pipeline_handle_event(*ctx.pipeline, event);
        }

        switch (event.type) {
            case SDL_EVENT_QUIT:
                ctx.running = false;
                break;

            case SDL_EVENT_KEY_DOWN:
                if (event.key.key == SDLK_ESCAPE) {
                    ctx.running = false;
                }
                if (event.key.key == SDLK_P) {
                    ctx.paused = !ctx.paused;
                }
                break;

            case SDL_EVENT_WINDOW_RESIZED:
                ctx.window_width = event.window.data1;
                ctx.window_height = event.window.data2;
                break;

            default:
                break;
        }
    }
}

void game_update(GameContext& ctx) {
    // Calculate delta time
    uint64_t current_time = SDL_GetPerformanceCounter();
    uint64_t freq = SDL_GetPerformanceFrequency();
    ctx.delta_time = static_cast<float>(current_time - ctx.last_time) / static_cast<float>(freq);
    ctx.last_time = current_time;

    // Clamp delta time to prevent spiral of death
    if (ctx.delta_time > 0.25f) {
        ctx.delta_time = 0.25f;
    }

    // Clear screen
    SDL_SetRenderDrawColor(ctx.renderer, 30, 30, 40, 255);
    SDL_RenderClear(ctx.renderer);

    if (!ctx.paused) {
        // Update pipeline and ECS only when not paused
        if (ctx.pipeline) {
            pipeline_update(*ctx.pipeline, ctx);
        }
        ctx.ecs.progress(ctx.delta_time);
    }

    // Always render so the display doesn't blank while paused
    if (ctx.pipeline) {
        pipeline_render(*ctx.pipeline, ctx);
    }

    SDL_RenderPresent(ctx.renderer);
}

void game_render(GameContext& ctx) {
    // Rendering is handled in game_update()
    (void)ctx;
}

bool game_loop(GameContext& ctx) {
    game_process_events(ctx);
    game_update(ctx);
    game_render(ctx);

    return ctx.running;
}
