#include "global_inputs.h"
#include <SDL3/SDL_render.h> // Para SDL_RendererLogicalPresentation, SDL_Se...
#include <string>            // Para operator+, allocator, char_traits, string
#include <vector>            // Para vector
#include "asset.h"           // Para Asset
#include "input.h"           // Para Input, InputAction, InputDeviceToUse
#include "audio.h"           // Para JA_SetMusicVolume, JA_SetSoundVolume
#include "lang.h"            // Para getText, Code, getNextLangCode, loadFro...
#include "notifier.h"        // Para Notifier
#include "options.h"         // Para Options, options, VideoOptions, GameOpt...
#include "param.h"           // Para Param, ParamGame, param
#include "screen.h"          // Para Screen
#include "section.h"         // Para Name, name, Options, options, AttractMode
#include "utils.h"           // Para boolToOnOff

namespace globalInputs
{
    // Variables
    int service_pressed_counter = 0;
    bool service_pressed = false;

    // Termina
    void quit(section::Options code)
    {
        const std::string CODE = "QUIT";
        if (Notifier::get()->checkCode(CODE))
        {
            // Si la notificación de salir está activa, cambia de sección
            section::name = section::Name::QUIT;
            section::options = code;
        }
        else
        {
            // Si la notificación de salir no está activa, muestra la notificación
#ifdef ARCADE
            const int INDEX = code == section::Options::QUIT_WITH_CONTROLLER ? 116 : 94;
            Notifier::get()->show({lang::getText(INDEX), std::string()}, -1, CODE);
#else
            Notifier::get()->show({lang::getText(94), std::string()}, -1, CODE);
#endif
        }
    }

    // Reinicia
    void reset()
    {
        const std::string CODE = "RESET";
        if (Notifier::get()->checkCode(CODE))
        {
            section::name = section::Name::INIT;
            Notifier::get()->show({lang::getText(111)});
        }
        else
        {
            Notifier::get()->show({lang::getText(125), std::string()}, -1, CODE);
        }
    }

    // Activa o desactiva el audio
    void toggleAudio()
    {
        options.audio.enabled = !options.audio.enabled;
        Audio::get().enable(options.audio.enabled);
        Notifier::get()->show({"Audio " + boolToOnOff(options.audio.enabled)});
    }

    // Cambia el modo de escalado entero
    void toggleIntegerScale()
    {
        Screen::get()->toggleIntegerScale();
        Notifier::get()->show({lang::getText(134) + " " + boolToOnOff(options.video.integer_scale)});
    }

    // Activa / desactiva el vsync
    void toggleVSync()
    {
        Screen::get()->toggleVSync();
        Notifier::get()->show({lang::getText(136) + " " + boolToOnOff(options.video.v_sync)});
    }

    // Activa o desactiva los shaders
    void toggleShaders()
    {
        Screen::get()->toggleShaders();
        Notifier::get()->show({lang::getText(135) + " " + boolToOnOff(options.video.shaders)});
    }

    // Obtiene una fichero a partir de un lang::Code
    std::string getLangFile(lang::Code code)
    {
        switch (code)
        {
        case lang::Code::ba_BA:
            return Asset::get().get("ba_BA.txt");
            break;
        case lang::Code::es_ES:
            return Asset::get().get("es_ES.txt");
            break;
        default:
            return Asset::get().get("en_UK.txt");
            break;
        }
    }

    // Obtiene una cadena a partir de un lang::Code
    std::string getLangName(lang::Code code)
    {
        switch (code)
        {
        case lang::Code::ba_BA:
            return " \"ba_BA\"";
            break;
        case lang::Code::es_ES:
            return " \"es_ES\"";
            break;
        default:
            return " \"en_UK\"";
            break;
        }
    }

    // Cambia el idioma
    void changeLang()
    {
        const std::string CODE = "LANG";
        if (Notifier::get()->checkCode(CODE))
        {
            options.game.language = lang::getNextLangCode(options.game.language);
            lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language)));
            section::name = section::Name::INIT;
            section::options = section::Options::RELOAD;
            Notifier::get()->show({lang::getText(127) + getLangName(options.game.language)});
        }
        else
        {
            const auto NEXT = lang::getNextLangCode(options.game.language);
            Notifier::get()->show({lang::getText(126) + getLangName(NEXT), std::string()}, -1, CODE);
        }
    }

    // Cambia el modo de disparo
    void toggleFireMode()
    {
        options.game.autofire = !options.game.autofire;
        Notifier::get()->show({lang::getText(130) + " " + boolToOnOff(options.game.autofire)});
    }

    // Salta una sección del juego
    void skip_section()
    {
        switch (section::name)
        {
        case section::Name::INTRO:
            Audio::get().stopMusic();
            /* Continua en el case de abajo */
        case section::Name::LOGO:
        case section::Name::HI_SCORE_TABLE:
        case section::Name::INSTRUCTIONS:
        {
            section::name = section::Name::TITLE;
            section::options = section::Options::TITLE_1;
            section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
            break;
        }
        default:
            break;
        }
    }

    // Comprueba los inputs que se pueden introducir en cualquier sección del juego
    void check()
    {
        // Teclado
        {
            // Comprueba el teclado para cambiar entre pantalla completa y ventana
            if (Input::get()->checkInput(InputAction::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                Screen::get()->toggleFullscreen();
                const std::string MODE = options.video.fullscreen ? lang::getText(133) : lang::getText(132);
                Notifier::get()->show({MODE});
                return;
            }

            // Comprueba el teclado para decrementar el tamaño de la ventana
            if (Input::get()->checkInput(InputAction::WINDOW_DEC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                if (Screen::get()->decWindowZoom())
                {
                    Notifier::get()->show({lang::getText(131) + " x" + std::to_string(options.window.zoom)});
                }
                return;
            }

            // Comprueba el teclado para incrementar el tamaño de la ventana
            if (Input::get()->checkInput(InputAction::WINDOW_INC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                if (Screen::get()->incWindowZoom())
                {
                    Notifier::get()->show({lang::getText(131) + " x" + std::to_string(options.window.zoom)});
                }
                return;
            }

            // Salir
            if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                quit(section::Options::QUIT_WITH_KEYBOARD);
                return;
            }

            // Saltar sección
            if (Input::get()->checkAnyButtonPressed())
            {
                skip_section();
                return;
            }

            // Reset
            if (Input::get()->checkInput(InputAction::RESET, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                reset();
                return;
            }

            // Audio
            if (Input::get()->checkInput(InputAction::TOGGLE_AUDIO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                toggleAudio();
                return;
            }

            // Autofire
            if (Input::get()->checkInput(InputAction::TOGGLE_AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                toggleFireMode();
                return;
            }

            // Idioma
            if (Input::get()->checkInput(InputAction::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                changeLang();
                return;
            }

            // Shaders
            if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                toggleShaders();
                return;
            }

            // Integer Scale
            if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                toggleIntegerScale();
                return;
            }

            // VSync
            if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_VSYNC, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                toggleVSync();
                return;
            }
#ifdef DEBUG
            // Debug info
            if (Input::get()->checkInput(InputAction::SHOW_INFO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                Screen::get()->toggleDebugInfo();
                return;
            }
#endif
            // OnScreenHelp
            if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
            {
                service_pressed = true;
                return;
            }
        }

        // Mandos
        {
            for (int i = 0; i < Input::get()->getNumControllers(); ++i)
            {
                // Salir
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) &&
                    Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    quit(section::Options::QUIT_WITH_CONTROLLER);
                    return;
                }

                // Reset
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) &&
                    Input::get()->checkInput(InputAction::RESET, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    reset();
                    return;
                }

                // Audio
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) &&
                    Input::get()->checkInput(InputAction::TOGGLE_AUDIO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    toggleAudio();
                    return;
                }

                // Shaders
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) &&
                    Input::get()->checkInput(InputAction::TOGGLE_VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    toggleShaders();
                    return;
                }
#ifdef DEBUG
                // Debug Info
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i) &&
                    Input::get()->checkInput(InputAction::SHOW_INFO, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    Screen::get()->toggleDebugInfo();
                    return;
                }
#endif
                // OnScreenHelp
                if (Input::get()->checkInput(InputAction::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
                {
                    service_pressed = true;
                    return;
                }
            }
        }
    }
}