#pragma once

#include <SDL3/SDL.h>

#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "core/input/input.hpp"
#include "game/ui/window_message.hpp"

namespace Options {
    struct Gamepad;
}

// --- Clase DefineButtons: configuración de botones de gamepad ---
class DefineButtons {
   public:
    // --- Estructuras ---
    struct Button {
        std::string label;
        Input::Action action;
        int button;

        Button(std::string label, Input::Action action, int button)
            : label(std::move(label)),
              action(action),
              button(button) {}
    };

    // --- Constructor y destructor ---
    DefineButtons();
    ~DefineButtons() = default;

    // --- Métodos principales ---
    void render();
    void update(float delta_time);
    void handleEvents(const SDL_Event& event);
    auto enable(Options::Gamepad* options_gamepad) -> bool;
    void disable();

    // --- Getters ---
    [[nodiscard]] auto isReadyToClose() const -> bool;
    [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
    [[nodiscard]] auto isFinished() const -> bool { return finished_; }

   private:
    // --- Constantes ---
    static constexpr float MESSAGE_DISPLAY_DURATION_S = 2.0F;  // Cuánto tiempo mostrar el mensaje en segundos

    // --- Objetos y punteros ---
    Input* input_ = nullptr;                         // Entrada del usuario
    Options::Gamepad* options_gamepad_ = nullptr;    // Opciones del gamepad
    std::unique_ptr<WindowMessage> window_message_;  // Mensaje de ventana

    // --- Variables de estado ---
    std::vector<Button> buttons_;                // Lista de botones
    std::vector<std::string> controller_names_;  // Nombres de los controladores
    size_t index_button_ = 0;                    // Índice del botón seleccionado
    float message_timer_ = 0.0F;                 // Timer en segundos para el mensaje
    bool enabled_ = false;                       // Flag para indicar si está activo
    bool finished_ = false;                      // Flag para indicar si ha terminado
    bool closing_ = false;                       // Flag para indicar que está cerrando
    bool message_shown_ = false;                 // Flag para indicar que ya mostró el mensaje
    bool l2_was_pressed_ = false;                // Estado anterior del trigger L2
    bool r2_was_pressed_ = false;                // Estado anterior del trigger R2

    // --- Métodos internos ---
    void incIndexButton();
    void doControllerButtonDown(const SDL_GamepadButtonEvent& event);
    void doControllerAxisMotion(const SDL_GamepadAxisEvent& event);
    void bindButtons(Options::Gamepad* options_gamepad);
    auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
    auto checkTriggerNotInUse(int trigger_button) -> bool;
    void clearButtons();
    void checkEnd();
    void updateWindowMessage();
};