#include "resource_manager.hpp"

#include <cstring>
#include <fstream>
#include <iostream>

#include "resource_pack.hpp"

// Inicializar estáticos
ResourcePack* ResourceManager::resourcePack_ = nullptr;
std::map<std::string, std::vector<unsigned char>> ResourceManager::cache_;

auto ResourceManager::init(const std::string& pack_file_path) -> bool {
    // Si ya estaba inicializado, liberar primero
    if (resourcePack_ != nullptr) {
        delete resourcePack_;
        resourcePack_ = nullptr;
    }

    // Intentar cargar el pack
    resourcePack_ = new ResourcePack();
    if (!resourcePack_->loadPack(pack_file_path)) {
        // Si falla, borrar instancia (usará fallback a disco)
        delete resourcePack_;
        resourcePack_ = nullptr;
        std::cout << "resources.pack no encontrado - usando carpeta data/" << '\n';
        return false;
    }

    std::cout << "resources.pack cargado (" << resourcePack_->getResourceCount() << " recursos)" << '\n';
    return true;
}

void ResourceManager::shutdown() {
    cache_.clear();
    if (resourcePack_ != nullptr) {
        delete resourcePack_;
        resourcePack_ = nullptr;
    }
}

auto ResourceManager::loadResource(const std::string& resource_path, unsigned char*& data, size_t& size) -> bool {
    data = nullptr;
    size = 0;

    // 1. Consultar caché en RAM (sin I/O)
    auto it = cache_.find(resource_path);
    if (it != cache_.end()) {
        size = it->second.size();
        data = new unsigned char[size];
        std::memcpy(data, it->second.data(), size);
        return true;
    }

    // 2. Intentar cargar desde pack (si está disponible)
    if (resourcePack_ != nullptr) {
        ResourcePack::ResourceData pack_data = resourcePack_->loadResource(resource_path);
        if (pack_data.data != nullptr) {
            cache_[resource_path] = std::vector<unsigned char>(pack_data.data, pack_data.data + pack_data.size);
            data = pack_data.data;
            size = pack_data.size;
            return true;
        }
    }

    // 3. Fallback: cargar desde disco
    std::ifstream file(resource_path, std::ios::binary | std::ios::ate);
    if (!file) {
        std::string data_path = "data/" + resource_path;
        file.open(data_path, std::ios::binary | std::ios::ate);
        if (!file) { return false; }
    }
    size = static_cast<size_t>(file.tellg());
    file.seekg(0, std::ios::beg);
    data = new unsigned char[size];
    file.read(reinterpret_cast<char*>(data), size);
    file.close();

    // Guardar en caché
    cache_[resource_path] = std::vector<unsigned char>(data, data + size);
    return true;
}

auto ResourceManager::isPackLoaded() -> bool {
    return resourcePack_ != nullptr;
}

auto ResourceManager::getResourceList() -> std::vector<std::string> {
    if (resourcePack_ != nullptr) {
        return resourcePack_->getResourceList();
    }
    return {};  // Vacío si no hay pack
}

auto ResourceManager::getResourceCount() -> size_t {
    if (resourcePack_ != nullptr) {
        return resourcePack_->getResourceCount();
    }
    return 0;
}
