// audio_cache.cpp - Implementació del caché de sons i música
// © 2025 Port a C++20 amb SDL3

#include "core/audio/audio_cache.hpp"

#include <iostream>

// Inicialització de variables estàtiques
std::unordered_map<std::string, JA_Sound_t*> AudioCache::sounds_;
std::unordered_map<std::string, JA_Music_t*> AudioCache::musics_;
std::string AudioCache::sounds_base_path_ = "data/sounds/";
std::string AudioCache::music_base_path_ = "data/music/";

JA_Sound_t* AudioCache::getSound(const std::string& name) {
    // Cache hit
    auto it = sounds_.find(name);
    if (it != sounds_.end()) {
        std::cout << "[AudioCache] Sound cache hit: " << name << std::endl;
        return it->second;
    }

    // Cache miss - cargar archivo
    std::string fullpath = resolveSoundPath(name);
    JA_Sound_t* sound = JA_LoadSound(fullpath.c_str());

    if (sound == nullptr) {
        std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << fullpath
                  << std::endl;
        return nullptr;
    }

    std::cout << "[AudioCache] Sound loaded: " << name << std::endl;
    sounds_[name] = sound;
    return sound;
}

JA_Music_t* AudioCache::getMusic(const std::string& name) {
    // Cache hit
    auto it = musics_.find(name);
    if (it != musics_.end()) {
        std::cout << "[AudioCache] Music cache hit: " << name << std::endl;
        return it->second;
    }

    // Cache miss - cargar archivo
    std::string fullpath = resolveMusicPath(name);
    JA_Music_t* music = JA_LoadMusic(fullpath.c_str());

    if (music == nullptr) {
        std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << fullpath
                  << std::endl;
        return nullptr;
    }

    std::cout << "[AudioCache] Music loaded: " << name << std::endl;
    musics_[name] = music;
    return music;
}

void AudioCache::clear() {
    std::cout << "[AudioCache] Clearing cache (" << sounds_.size() << " sounds, "
              << musics_.size() << " music)" << std::endl;

    // Liberar memoria de sonidos
    for (auto& [name, sound] : sounds_) {
        if (sound && sound->buffer) {
            SDL_free(sound->buffer);
        }
        delete sound;
    }
    sounds_.clear();

    // Liberar memoria de música
    for (auto& [name, music] : musics_) {
        if (music && music->buffer) {
            SDL_free(music->buffer);
        }
        if (music && music->filename) {
            free(music->filename);
        }
        delete music;
    }
    musics_.clear();
}

size_t AudioCache::getSoundCacheSize() { return sounds_.size(); }

size_t AudioCache::getMusicCacheSize() { return musics_.size(); }

std::string AudioCache::resolveSoundPath(const std::string& name) {
    // Si es un path absoluto (comienza con '/'), usarlo directamente
    if (!name.empty() && name[0] == '/') {
        return name;
    }

    // Si ya contiene el prefix base_path, usarlo directamente
    if (name.find(sounds_base_path_) == 0) {
        return name;
    }

    // Caso contrario, añadir base_path
    return sounds_base_path_ + name;
}

std::string AudioCache::resolveMusicPath(const std::string& name) {
    // Si es un path absoluto (comienza con '/'), usarlo directamente
    if (!name.empty() && name[0] == '/') {
        return name;
    }

    // Si ya contiene el prefix base_path, usarlo directamente
    if (name.find(music_base_path_) == 0) {
        return name;
    }

    // Caso contrario, añadir base_path
    return music_base_path_ + name;
}
