// audio_adapter.cpp - Implementación de AudioResource para orni_attack
// © 2026 JailDesigner
//
// 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.
auto musicCache() -> std::unordered_map<std::string, std::unique_ptr<Ja::Music>>& {
    static std::unordered_map<std::string, std::unique_ptr<Ja::Music>> cache_;
    return cache_;
}

auto soundCache() -> std::unordered_map<std::string, std::unique_ptr<Ja::Sound>>& {
    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"
auto normalizeMusicPath(const std::string& name) -> std::string {
    return (name.starts_with("music/")) ? name : "music/" + name;
}

auto normalizeSoundPath(const std::string& name) -> std::string {
    return (name.starts_with("sounds/")) ? 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
