#include "core/system/global_events.hpp"

#include "core/input/input.hpp"  // Para Input (gamepad add/remove)
#include "core/input/mouse.hpp"
#include "core/locale/locale.hpp"  // Para Locale
#include "game/options.hpp"        // Para Options, options, OptionsGame, OptionsAudio
#include "game/scene_manager.hpp"  // Para SceneManager::current (filtrar BACK a GAME)
#include "game/ui/console.hpp"     // Para Console
#include "game/ui/notifier.hpp"    // Para Notifier

namespace GlobalEvents {

    namespace {
        // Flag per saber si en aquest frame s'ha rebut un button down del gamepad.
        // El consumeix GlobalInputs perquè un botó del comandament salti escenes.
        bool gamepad_button_pressed = false;
    }  // namespace

    // Comprueba los eventos que se pueden producir en cualquier sección del juego.
    // Nota: SDL_EVENT_QUIT el gestiona Director::handleEvent() directament.
    void handle(const SDL_Event& event) {
        if (event.type == SDL_EVENT_RENDER_DEVICE_RESET || event.type == SDL_EVENT_RENDER_TARGETS_RESET) {
            // reLoadTextures();
        }

        // Connexió/desconnexió de gamepads: cal enrutar-los a Input perquè
        // afegisca el dispositiu a gamepads_. Sense això, en wasm els gamepads
        // mai es detecten (la Gamepad API del navegador només els exposa
        // després que l'usuari els active, més tard que el discoverGamepads
        // inicial). En desktop també arregla la connexió en calent.
        if (event.type == SDL_EVENT_GAMEPAD_ADDED || event.type == SDL_EVENT_GAMEPAD_REMOVED) {
            if (Input::get() != nullptr) {
                std::string name = Input::get()->handleEvent(event);
                if (!name.empty() && Notifier::get() != nullptr && Locale::get() != nullptr) {
                    const std::string KEY = (event.type == SDL_EVENT_GAMEPAD_ADDED)
                        ? "ui.gamepad_connected"
                        : "ui.gamepad_disconnected";
                    Notifier::get()->show({name + " " + Locale::get()->get(KEY)});
                }
            }
        }

        // Marcar polsació de qualsevol botó del comandament (els consumirà GlobalInputs
        // per saltar escenes d'attract mode). Queden exclosos els botons reservats a
        // accions globals perquè el "any button → ACCEPT" no se'ls mengi abans que
        // checkAction() els pugui enrutar:
        //   - BACK → EXIT (a emscripten només a l'escena GAME, ja que no pot tancar).
        //   - LEFT_SHOULDER / RIGHT_SHOULDER → NEXT_PALETTE / NEXT_PALETTE_SORT.
        if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
            const auto BUTTON = event.gbutton.button;
            const bool IS_BACK = (BUTTON == SDL_GAMEPAD_BUTTON_BACK);
            const bool IS_SHOULDER = (BUTTON == SDL_GAMEPAD_BUTTON_LEFT_SHOULDER || BUTTON == SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER);
#ifdef __EMSCRIPTEN__
            const bool RESERVE_BACK = IS_BACK && SceneManager::current == SceneManager::Scene::GAME;
#else
            const bool RESERVE_BACK = IS_BACK;
#endif
            if (!RESERVE_BACK && !IS_SHOULDER) {
                gamepad_button_pressed = true;
            }
        }

        // Enrutar eventos de texto a la consola cuando está activa
        if (Console::get() != nullptr && Console::get()->isActive()) {
            if (event.type == SDL_EVENT_TEXT_INPUT || event.type == SDL_EVENT_KEY_DOWN) {
                Console::get()->handleEvent(event);
                return;
            }
        }

        Mouse::handleEvent(event);
    }

    auto consumeGamepadButtonPressed() -> bool {
        const bool RESULT = gamepad_button_pressed;
        gamepad_button_pressed = false;
        return RESULT;
    }
}  // namespace GlobalEvents