/**
 * @file events_manager.c
 * @author Piotr Krygier (piotrkrygier@everyonencancode.xyz)
 * @brief Events manager for Red Scarf Engine
 * @version 0.1
 * @date 2026-03-02
 *
 * @copyright Copyright (c) 2026
 *
 */

#include "SDL3/SDL_events.h"
#include "SDL3/SDL_log.h"
#include "SDL3/SDL_mouse.h"
#include "events_context.h"
#include "rse_events_manager.h"
#include "utilities/commons.h"
#include "utilities/errors_common.h"

static rse_err_t default_event(void* args)
{
    (void)args;

    return RSE_ERROR_NO_ERROR;
}

static rse_err_t run_custom_event_handler(struct events_context_t* context,
                                          enum EVENT_HANDLER event_handler,
                                          void* args)
{
    return context->event_handlers[event_handler](args);
}

static rse_err_t quit_event(struct events_context_t* context)
{
    context->should_stop = EVENT_SHOULD_STOP_ENGINE_TRUE;

    return run_custom_event_handler(context, EVENT_HANDLER_QUIT, NULL);
}

static rse_err_t mouse_event(struct events_context_t* context)
{
    struct mouse_event_data_t mouse_data = {0};

    mouse_data.mouse_buttons = SDL_GetMouseState(&mouse_data.x_pos, &mouse_data.y_pos);

    return run_custom_event_handler(context, EVENT_HANDLER_MOUSE, (void*)&mouse_data);
}

rse_err_t rse_events_init(struct events_context_t* events_context)
{
    size_t i = 0U;

    for (i = 0U; i < EVENT_HANDLER_LAST; ++i) {
        events_context->event_handlers[i] = default_event;
    }

    return RSE_ERROR_NO_ERROR;
}

rse_err_t rse_events_set_event_handler(struct events_context_t* events_context,
                                       enum EVENT_HANDLER event_type,
                                       rse_event_handler_t event_handler)
{
    if (event_type >= EVENT_HANDLER_LAST) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Invalid event type selected");

        return RSE_ERROR_INVALID_PARAM;
    }

    if (event_handler == NULL) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided NULL event handler");

        return RSE_ERROR_INVALID_PARAM;
    }

    events_context->event_handlers[event_type] = event_handler;

    return RSE_ERROR_NO_ERROR;
}

rse_err_t rse_events_main_loop(struct events_context_t* context)
{
    SDL_Event event;
    rse_err_t status = RSE_ERROR_NO_ERROR;

    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_EVENT_QUIT:
                STATUS_CHECK(quit_event(context));
                break;
            case SDL_EVENT_MOUSE_BUTTON_DOWN:
                STATUS_CHECK(mouse_event(context));
                break;
        }
    }

    return status;
}
