#pragma once

#include <cmath>    // Para std::lround
#include <cstdint>  // Para int8_t, uint8_t
#include <string>   // Para string
#include <utility>  // Para move

namespace Ja {
    struct Music;
    struct Sound;
}  // namespace Ja

// --- Clase Audio: gestor de audio (singleton) ---
// Implementació canònica, byte-idèntica entre projectes.
// Els volums es manegen internament com a float 0.0–1.0; la capa de
// presentació (menús, notificacions) usa les helpers toPercent/fromPercent
// per mostrar 0–100 a l'usuari.
class Audio {
   public:
    // --- Enums ---
    enum class Group : std::int8_t {
        ALL = -1,      // Todos los grupos
        GAME = 0,      // Sonidos del juego
        INTERFACE = 1  // Sonidos de la interfaz
    };

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

    // --- Constantes ---
    static constexpr float MAX_VOLUME = 1.0F;          // Volumen máximo (float 0..1)
    static constexpr float MIN_VOLUME = 0.0F;          // Volumen mínimo (float 0..1)
    static constexpr float VOLUME_STEP = 0.05F;        // Pas estàndard per a UI (5%)
    static constexpr int FREQUENCY = 48000;            // Frecuencia de audio
    static constexpr int DEFAULT_CROSSFADE_MS = 1500;  // Duració del crossfade per defecte (ms)

    // --- 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

    static void update();  // Actualización del sistema de audio

    // --- Control de música ---
    void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0);  // Reproducir música por nombre (con crossfade opcional)
    void playMusic(Ja::Music* music, int loop = -1, int crossfade_ms = 0);         // Reproducir música por puntero (con crossfade opcional)
    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 por nombre
    void playSound(Ja::Sound* sound, Group group = Group::GAME) const;         // Reproducir sonido puntual por puntero
    void stopAllSounds() const;                                                // Detener todos los sonidos

    // --- Control de volumen (API interna: float 0.0..1.0) ---
    void setSoundVolume(float volume, Group group = Group::ALL) const;  // Ajustar volumen de efectos
    void setMusicVolume(float volume) const;                            // Ajustar volumen de música

    // --- Helpers de conversió per a la capa de presentació ---
    // UI (menús, notificacions) manega enters 0..100; internament viu float 0..1.
    static auto toPercent(float volume) -> int {
        return static_cast<int>(std::lround(volume * 100.0F));
    }
    static constexpr auto fromPercent(int percent) -> float {
        return static_cast<float>(percent) / 100.0F;
    }

    // --- 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

    // --- Consultas de estado ---
    [[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;
    [[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; }

   private:
    // --- Tipos anidados ---
    struct Music {
        MusicState state{MusicState::STOPPED};  // Estado actual de la música
        std::string name;                       // Última pista de música reproducida
        bool loop{false};                       // Indica si se reproduce en bucle
    };

    // --- Métodos ---
    Audio();              // Constructor privado
    ~Audio();             // Destructor privado
    void initSDLAudio();  // Inicializa SDL Audio

    // --- Variables miembro ---
    static Audio* instance;  // Instancia única de Audio

    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
};
