#include "AudioPlayerAsync.h"
#include <iostream>

#ifdef __EMSCRIPTEN__
AudioPlayerAsync::AudioPlayerAsync() {}
#else
AudioPlayerAsync::AudioPlayerAsync() : worker(&AudioPlayerAsync::workerThread, this) {}
#endif

AudioPlayerAsync::~AudioPlayerAsync() {
#ifndef __EMSCRIPTEN__
    {
        std::unique_lock<std::mutex> lock(mtx);
        stop = true;
        cv.notify_all();
    }
    if (worker.joinable())
        worker.join();
#endif
    shutdown();
}

bool AudioPlayerAsync::init() {
    if (initialized) return true;

    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
        std::cerr << "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: " << SDL_GetError() << std::endl;
        return false;
    }

    if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
        std::cerr << "Mix_OpenAudio failed: " << Mix_GetError() << std::endl;
        return false;
    }

    Mix_AllocateChannels(16);

    initialized = true;
    std::cout << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl;
    return true;
}

void AudioPlayerAsync::shutdown() {
    if (!initialized) return;

    {
        std::lock_guard<std::mutex> lock(soundCacheMutex);
        for (auto& pair : soundCache) {
            Mix_FreeChunk(pair.second);
        }
        soundCache.clear();
    }

    Mix_CloseAudio();
    SDL_QuitSubSystem(SDL_INIT_AUDIO);
    initialized = false;
    std::cout << "AudioPlayerAsync shutdown" << std::endl;
}

void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, int channel) {
    if (!initialized) {
        std::cerr << "AudioPlayerAsync not initialized" << std::endl;
        return;
    }

    auto task = [this, filePath, loops, channel]() {
        Mix_Chunk* sound = nullptr;
        {
            std::lock_guard<std::mutex> cacheLock(soundCacheMutex);
            auto it = soundCache.find(filePath);
            if (it != soundCache.end()) {
                sound = it->second;
            }
        }

        if (!sound) {
            sound = Mix_LoadWAV(filePath.c_str());
            if (!sound) {
                std::cerr << "Failed to load sound " << filePath << ": " << Mix_GetError() << std::endl;
                return;
            }
            std::lock_guard<std::mutex> cacheLock(soundCacheMutex);
            soundCache[filePath] = sound;
        }

        int result = Mix_PlayChannel(channel, sound, loops);
        if (result == -1) {
            std::cerr << "Mix_PlayChannel failed: " << Mix_GetError() << std::endl;
        }
    };

#ifdef __EMSCRIPTEN__
    task();
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push(std::move(task));
    cv.notify_one();
#endif
}

void AudioPlayerAsync::playMusicAsync(const std::string& filePath, int loops) {
    if (!initialized) return;

    auto task = [filePath, loops]() {
        Mix_Music* music = Mix_LoadMUS(filePath.c_str());
        if (!music) {
            std::cerr << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
            return;
        }
        if (Mix_PlayMusic(music, loops) == -1) {
            std::cerr << "Mix_PlayMusic failed: " << Mix_GetError() << std::endl;
            Mix_FreeMusic(music);
        }
    };

#ifdef __EMSCRIPTEN__
    task();
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push(std::move(task));
    cv.notify_one();
#endif
}

void AudioPlayerAsync::stopMusicAsync() {
    if (!initialized) return;
#ifdef __EMSCRIPTEN__
    Mix_HaltMusic();
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push([]() {
        Mix_HaltMusic();
        });
    cv.notify_one();
#endif
}

void AudioPlayerAsync::pauseMusicAsync() {
    if (!initialized) return;
#ifdef __EMSCRIPTEN__
    Mix_PauseMusic();
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push([]() {
        Mix_PauseMusic();
        });
    cv.notify_one();
#endif
}

void AudioPlayerAsync::resumeMusicAsync() {
    if (!initialized) return;
#ifdef __EMSCRIPTEN__
    Mix_ResumeMusic();
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push([]() {
        Mix_ResumeMusic();
        });
    cv.notify_one();
#endif
}

void AudioPlayerAsync::setMusicVolume(int volume) {
    if (!initialized) return;
    volume = std::max(0, std::min(128, volume));
#ifdef __EMSCRIPTEN__
    Mix_VolumeMusic(volume);
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push([volume]() {
        Mix_VolumeMusic(volume);
        });
    cv.notify_one();
#endif
}

void AudioPlayerAsync::setSoundVolume(int volume) {
    if (!initialized) return;
    volume = std::max(0, std::min(128, volume));
#ifdef __EMSCRIPTEN__
    Mix_Volume(-1, volume);
#else
    std::unique_lock<std::mutex> lock(mtx);
    taskQueue.push([volume]() {
        Mix_Volume(-1, volume); // все каналы
        });
    cv.notify_one();
#endif
}

#ifndef __EMSCRIPTEN__
void AudioPlayerAsync::workerThread() {
    while (true) {
        std::function<void()> task;
        {
            std::unique_lock<std::mutex> lock(mtx);
            cv.wait(lock, [this] { return !taskQueue.empty() || stop; });
            if (stop && taskQueue.empty())
                break;
            task = std::move(taskQueue.front());
            taskQueue.pop();
        }
        task();
    }
}
#endif
