// audio_adapter.cpp - Implementación de AudioResource para orni_attack
// © 2025 Orni Attack
//
// Implementa AudioResource::getMusic / getSound delegando a
// Resource::Helper::loadFile (que abstrae el resources.pack y el fallback
// a filesystem). Cache local de Ja::Music* / Ja::Sound* con lazy load:
// cada recurso se carga la primera vez que se pide y se mantiene vivo
// hasta el shutdown.

#include "core/audio/audio_adapter.hpp"

#include <cstdint>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>

#include "core/audio/jail_audio.hpp"
#include "core/resources/resource_helper.hpp"

namespace {

// Cachés locales: indexados por nombre lógico ("title.ogg", "effects/laser_shoot.wav", etc.)
// Mantienen ownership con unique_ptr; se liberan al salir del programa.
std::unordered_map<std::string, std::unique_ptr<Ja::Music>>& musicCache() {
    static std::unordered_map<std::string, std::unique_ptr<Ja::Music>> cache;
    return cache;
}

std::unordered_map<std::string, std::unique_ptr<Ja::Sound>>& soundCache() {
    static std::unordered_map<std::string, std::unique_ptr<Ja::Sound>> cache;
    return cache;
}

// Normaliza el nombre añadiendo la subcarpeta correspondiente si no la trae:
//   "title.ogg"            -> "music/title.ogg"
//   "music/title.ogg"      -> "music/title.ogg"
//   "effects/laser.wav"    -> "sounds/effects/laser.wav"
std::string normalizeMusicPath(const std::string& name) {
    return (name.rfind("music/", 0) == 0) ? name : "music/" + name;
}

std::string normalizeSoundPath(const std::string& name) {
    return (name.rfind("sounds/", 0) == 0) ? name : "sounds/" + name;
}

}  // namespace

namespace AudioResource {

auto getMusic(const std::string& name) -> Ja::Music* {
    auto& cache = musicCache();
    if (auto it = cache.find(name); it != cache.end()) {
        return it->second.get();
    }

    const std::string path = normalizeMusicPath(name);
    auto bytes = Resource::Helper::loadFile(path);
    if (bytes.empty()) {
        std::cerr << "[AudioResource] no se ha podido cargar música: " << path << "\n";
        return nullptr;
    }

    Ja::Music* raw = Ja::loadMusic(bytes.data(), static_cast<std::uint32_t>(bytes.size()), name.c_str());
    if (raw == nullptr) {
        std::cerr << "[AudioResource] decodificación de música falló: " << path << "\n";
        return nullptr;
    }

    cache.emplace(name, std::unique_ptr<Ja::Music>(raw));
    std::cout << "[AudioResource] música cargada: " << path << "\n";
    return raw;
}

auto getSound(const std::string& name) -> Ja::Sound* {
    auto& cache = soundCache();
    if (auto it = cache.find(name); it != cache.end()) {
        return it->second.get();
    }

    const std::string path = normalizeSoundPath(name);
    auto bytes = Resource::Helper::loadFile(path);
    if (bytes.empty()) {
        std::cerr << "[AudioResource] no se ha podido cargar sonido: " << path << "\n";
        return nullptr;
    }

    Ja::Sound* raw = Ja::loadSound(bytes.data(), static_cast<std::uint32_t>(bytes.size()));
    if (raw == nullptr) {
        std::cerr << "[AudioResource] decodificación de sonido falló: " << path << "\n";
        return nullptr;
    }

    cache.emplace(name, std::unique_ptr<Ja::Sound>(raw));
    std::cout << "[AudioResource] sonido cargado: " << path << "\n";
    return raw;
}

}  // namespace AudioResource
