#include "jaudio.h"
#include "jail_audio.h"
#include <SDL2/SDL.h>
#include <stdio.h>
#include "jfile.h"
#include <vector>
#include "config.h"

namespace audio
{
    struct sound_cache_t
    {
        std::string name;
        JA_Sound_t *chunk;
    };

    //char *music_buffer = nullptr;
    JA_Music_t *music = nullptr;
    std::vector<sound_cache_t> sounds;
    std::string musica_actual = "";

    // Inicialitza el sistema de só
    void init()
    {
        JA_Init(48000, AUDIO_S16, 2);
        //Mix_Init(MIX_INIT_OGG);// | MIX_INIT_WAVPACK);
        //Mix_OpenAudio(48000, AUDIO_S16, 2, 512);
    }

    // Tanca el sistema de só (no shit, sherlock)
    void quit()
    {
        if (music) JA_DeleteMusic(music);
        for (auto sound : sounds) JA_DeleteSound(sound.chunk); // Mix_FreeChunk(sound.chunk);
        sounds.clear();
        JA_Quit(); // Mix_CloseAudio();
    }

    // Comença a reproduïr la música en questió
    void playMusic(const std::string filename, const int loop)
    {
        if (!config::isMusicEnabled()) return;
        // Si hi havia musica carregada, alliberem memòria
        //if (music_buffer) free(music_buffer);
        if (music) JA_DeleteMusic(music); //Mix_FreeMusic(music);

        int size;
        char *buffer = file::getFileBuffer(filename, size);
        music = JA_LoadMusic((uint8_t*)buffer, size);
        free(buffer);
        //auto rwops = SDL_RWFromMem(music_buffer, size);
        //auto mus = Mix_LoadMUS_RW(rwops, 1);
        //free(music_buffer); // [RZC 03/10/2024] Si allibere el buffer, no funciona la música. Porca miseria! Per aixó l'allibere abans de carregar si ja estava usat.
        //Mix_PlayMusic((Mix_Music *)mus, loop);
        JA_PlayMusic(music, loop);
        musica_actual = filename;
    }

    // Pausa la música que està sonant ara
    void pauseMusic()
    {
        JA_PauseMusic(); //Mix_PauseMusic();
    }

    // Continua la música pausada
    void resumeMusic()
    {
        if (!config::isMusicEnabled()) return;
        JA_ResumeMusic(); //Mix_ResumeMusic();
    }

    // Para la música que estava sonant
    void stopMusic()
    {
        JA_StopMusic(); //Mix_HaltMusic();
        musica_actual = "";
    }

    // Obté el estat actual de la música
    const music_state getMusicState()
    {
        if (JA_GetMusicState() == JA_MUSIC_PAUSED)
        {
            return MUSIC_PAUSED;
        }
        else if (JA_GetMusicState() == JA_MUSIC_PLAYING)
        {
            return MUSIC_PLAYING;
        }
        else
        {
            return MUSIC_STOPPED;
        }
    }

    // Obté el nom de la música actual
    const std::string getCurrentMusic()
    {
        return musica_actual;
    }



    // Carrega un só des d'un arxiu WAV
    void loadSound(const std::string filename)
    {
        int size;
        char *buffer = file::getFileBuffer(filename, size);
        auto chunk = JA_LoadSound((uint8_t *)buffer, size);
        free(buffer);

        //auto chunk = Mix_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1);
        //if (!chunk) printf("ERROR: %s\n", SDL_GetError());
        sound_cache_t sound = { filename, chunk };
        sounds.push_back(sound);
    }

    // Comença a reproduïr el só especificat
    const int playSound(const std::string name, const int priority, const int loop)
    {
        if (priority < config::getSoundMode()) return -1;
        for (auto sound : sounds)
        {
            if (sound.name == name) return JA_PlaySound(sound.chunk, loop); // Mix_PlayChannel(-1, sound.chunk, loop);
        }
        return -1;
    }

    // Pausa un canal en el que s'estava reproduïnt un só
    void pauseChannel(const int channel)
    {
        if (channel == -1) return;
        JA_PauseChannel(channel); // Mix_Pause(channel);
    }

    // Continua un canal pausat
    void resumeChannel(const int channel)
    {
        if (channel == -1) return;
        JA_ResumeChannel(channel); // Mix_Resume(channel);
    }

    // Para un canal que estava reproduïnt un só
    void stopChannel(const int channel)
    {
        if (channel == -1) return;
        JA_StopChannel(channel); // Mix_HaltChannel(channel);
    }

    // Para tots els canals
    void stopAllChannel()
    {
        JA_StopChannel(-1); // Mix_HaltChannel(-1);
    }

    // Obté l'estat d'un canal
    const channel_state getChannelState(const int channel)
    {
        if (JA_GetChannelState(channel) == JA_CHANNEL_PAUSED)
        {
            return CHANNEL_PAUSED;
        }
        else if (JA_GetChannelState(channel) == JA_CHANNEL_PLAYING)
        {
            return CHANNEL_PLAYING;
        }
        else
        {
            return CHANNEL_FREE;
        }
    }

    // Estableix el volum general
    const int setVolume(int volume)
    {
        return JA_SetVolume(volume); // Mix_Volume(-1, volume);
    }
}