#pragma once

#include <SDL3/SDL.h>  // Para SDL_Event

#include <cstddef>     // Para size_t
#include <cstdint>     // Para std::uint8_t
#include <functional>  // Para function
#include <iterator>    // Para pair
#include <memory>      // Para unique_ptr
#include <string>      // Para basic_string, string
#include <utility>     // Para pair
#include <vector>      // Para vector

#include "core/input/define_buttons.hpp"  // for DefineButtons
#include "game/ui/ui_message.hpp"         // for UIMessage

class MenuOption;
class MenuRenderer;

class ServiceMenu {
   public:
    // --- Enums y constantes ---
    enum class SettingsGroup : std::uint8_t {
        CONTROLS,
        VIDEO,
        AUDIO,
        SETTINGS,
        SYSTEM,
        MAIN
    };
    enum class GroupAlignment : std::uint8_t {
        CENTERED,
        LEFT
    };
    static constexpr size_t OPTIONS_HORIZONTAL_PADDING = 20;
    static constexpr size_t MIN_WIDTH = 240;
    static constexpr size_t MIN_GAP_OPTION_VALUE = 30;
    static constexpr size_t SETTINGS_GROUP_SIZE = 6;

    using StateChangeCallback = std::function<void(bool is_active)>;

    // --- Métodos de singleton ---
    static void init();
    static void destroy();
    static auto get() -> ServiceMenu*;
    ServiceMenu(const ServiceMenu&) = delete;
    auto operator=(const ServiceMenu&) -> ServiceMenu& = delete;

    // --- Métodos principales ---
    void toggle();
    void render();
    void update(float delta_time);
    void reset();

    // --- Lógica de navegación ---
    void setSelectorUp();
    void setSelectorDown();
    void adjustOption(bool adjust_up);
    void selectOption();
    void moveBack();

    // --- Método para manejar eventos ---
    void handleEvent(const SDL_Event& event);
    auto checkInput() -> bool;

    // --- Método principal para refresco externo ---
    void refresh();  // Refresca los valores y el layout del menú bajo demanda

    // --- Método para registrar el callback ---
    void setStateChangeCallback(StateChangeCallback callback);

    // --- Getters para el estado ---
    [[nodiscard]] auto isDefiningButtons() const -> bool;
    [[nodiscard]] auto isAnimating() const -> bool;  // Nuevo getter

    // --- Getters para que el Renderer pueda leer el estado ---
    [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
    [[nodiscard]] auto getTitle() const -> const std::string& { return title_; }
    [[nodiscard]] auto getCurrentGroup() const -> SettingsGroup { return current_settings_group_; }
    [[nodiscard]] auto getCurrentGroupAlignment() const -> GroupAlignment;
    [[nodiscard]] auto getDisplayOptions() const -> const std::vector<MenuOption*>& { return display_options_; }
    [[nodiscard]] auto getAllOptions() const -> const std::vector<std::unique_ptr<MenuOption>>& { return options_; }
    [[nodiscard]] auto getSelectedIndex() const -> size_t { return selected_; }
    [[nodiscard]] auto getOptionPairs() const -> const std::vector<std::pair<std::string, std::string>>& { return option_pairs_; }
    [[nodiscard]] auto countOptionsInGroup(SettingsGroup group) const -> size_t;

   private:
    bool enabled_ = false;
    std::vector<std::unique_ptr<MenuOption>> options_;
    std::vector<MenuOption*> display_options_;
    std::vector<std::pair<std::string, std::string>> option_pairs_;
    SettingsGroup current_settings_group_;
    SettingsGroup previous_settings_group_;
    std::string title_;
    size_t selected_ = 0;
    size_t main_menu_selected_ = 0;
    std::unique_ptr<UIMessage> restart_message_ui_;
    bool last_pending_changes_ = false;
    std::unique_ptr<DefineButtons> define_buttons_;
    std::unique_ptr<MenuRenderer> renderer_;
    StateChangeCallback state_change_callback_;

    // --- Métodos de lógica interna ---
    void updateDisplayOptions();
    void updateOptionPairs();
    void initializeOptions();
    void updateMenu();
    void applySettings();
    void applyControlsSettings();
    void applyVideoSettings();
    static void applyAudioSettings();
    void applySettingsSettings();
    [[nodiscard]] auto getOptionByCaption(const std::string& caption) const -> MenuOption*;
    void adjustListValues();
    static void playMoveSound();
    static void playAdjustSound();
    static void playSelectSound();
    static void playBackSound();
    [[nodiscard]] static auto settingsGroupToString(SettingsGroup group) -> std::string;
    void setHiddenOptions();
    void setEnabledInternal(bool enabled);  //  Método privado para cambiar estado y notificar

    // --- Constructores y destructor privados (singleton) ---
    ServiceMenu();
    ~ServiceMenu() = default;

    // --- Instancia singleton ---
    static ServiceMenu* instance;
};