#pragma once

#include <string>   // Para string
#include <utility>  // Para move

// --- Clase Audio: gestor de audio (singleton) ---
class Audio {
    public:
        // --- Enums ---
        enum class Group : int {
            ALL = -1,      // Todos los grupos
            GAME = 0,      // Sonidos del juego
            INTERFACE = 1  // Sonidos de la interfaz
        };

        enum class MusicState {
            PLAYING,  // Reproduciendo música
            PAUSED,   // Música pausada
            STOPPED,  // Música detenida
        };

        // --- Constantes ---
        static constexpr int MAX_VOLUME = 100;   // Volumen máximo
        static constexpr int MIN_VOLUME = 0;     // Volumen mínimo
        static constexpr int FREQUENCY = 48000;  // Frecuencia de audio

        // --- Métodos de singleton ---
        static void init();                               // Inicializa el objeto Audio
        static void destroy();                            // Libera el objeto Audio
        static auto get() -> Audio*;                      // Obtiene el puntero al objeto Audio
        Audio(const Audio&) = delete;                     // Evitar copia
        auto operator=(const Audio&) -> Audio& = delete;  // Evitar asignación

        // --- Método principal ---
        static void update();

        // --- Control de Música ---
        void playMusic(const std::string& name, int loop = -1);  // Reproducir música en bucle
        void pauseMusic();                                       // Pausar reproducción de música
        void resumeMusic();                                      // Continua la música pausada
        void stopMusic();                                        // Detener completamente la música
        void fadeOutMusic(int milliseconds) const;               // Fundido de salida de la música

        // --- Control de Sonidos ---
        void playSound(const std::string& name, Group group = Group::GAME) const;  // Reproducir sonido puntual
        void stopAllSounds() const;                                                // Detener todos los sonidos

        // --- Configuración General ---
        void enable(bool value);                        // Establecer estado general
        void toggleEnabled() { enabled_ = !enabled_; }  // Alternar estado general
        void applySettings();                           // Aplica la configuración

        // --- Configuración de Sonidos ---
        void enableSound() { sound_enabled_ = true; }             // Habilitar sonidos
        void disableSound() { sound_enabled_ = false; }           // Deshabilitar sonidos
        void enableSound(bool value) { sound_enabled_ = value; }  // Establecer estado de sonidos
        void toggleSound() { sound_enabled_ = !sound_enabled_; }  // Alternar estado de sonidos

        // --- Configuración de Música ---
        void enableMusic() { music_enabled_ = true; }             // Habilitar música
        void disableMusic() { music_enabled_ = false; }           // Deshabilitar música
        void enableMusic(bool value) { music_enabled_ = value; }  // Establecer estado de música
        void toggleMusic() { music_enabled_ = !music_enabled_; }  // Alternar estado de música

        // --- Control de Volumen ---
        void setSoundVolume(int volume, Group group = Group::ALL) const;  // Ajustar volumen de efectos
        void setMusicVolume(int volume) const;                            // Ajustar volumen de música

        // --- Getters para debug ---
        [[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
        [[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; }
        [[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; }
        [[nodiscard]] auto getMusicState() const -> MusicState { return music_.state; }
        [[nodiscard]] static auto getRealMusicState() -> MusicState;  // Consulta directamente a jailaudio
        [[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; }

    private:
        // --- Estructuras privadas ---
        struct Music {
                MusicState state;  // Estado actual de la música (reproduciendo, detenido, en pausa)
                std::string name;  // Última pista de música reproducida
                bool loop;         // Indica si la última pista de música se debe reproducir en bucle

                // Constructor para inicializar la música con valores predeterminados
                Music()
                    : state(MusicState::STOPPED),
                      loop(false) {}

                // Constructor para inicializar con valores específicos
                Music(MusicState init_state, std::string init_name, bool init_loop)
                    : state(init_state),
                      name(std::move(init_name)),
                      loop(init_loop) {}
        };

        // --- Variables de estado ---
        Music music_;                // Estado de la música
        bool enabled_ = true;        // Estado general del audio
        bool sound_enabled_ = true;  // Estado de los efectos de sonido
        bool music_enabled_ = true;  // Estado de la música

        // --- Métodos internos ---
        void initSDLAudio();  // Inicializa SDL Audio

        // --- Constructores y destructor privados (singleton) ---
        Audio();   // Constructor privado
        ~Audio();  // Destructor privado

        // --- Instancia singleton ---
        static Audio* instance;  // Instancia única de Audio
};