#pragma once

#include <string>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <future>
#include <functional>

namespace resources {

class ResourceManager {
public:
    ResourceManager();
    ~ResourceManager();

    // Return cached resource if available and of the right type
    template<typename T>
    std::shared_ptr<T> get(const std::string& key)
    {
        std::lock_guard<std::mutex> lk(mutex_);
        auto it = cache_.find(key);
        if (it == cache_.end()) return nullptr;
        auto sp = it->second;
        if (!sp) { cache_.erase(it); return nullptr; }
        return std::static_pointer_cast<T>(sp);
    }

    // Asynchronously load a resource using the provided loader function.
    // The loader must return a shared_ptr to the concrete resource (boxed as void).
    std::future<std::shared_ptr<void>> loadAsync(const std::string& key, std::function<std::shared_ptr<void>(const std::string&)> loader);

    // Insert a resource into the cache (thread-safe)
    void put(const std::string& key, std::shared_ptr<void> resource);

private:
    // Keep strong ownership of cached resources so they remain valid
    // while present in the cache.
    std::unordered_map<std::string, std::shared_ptr<void>> cache_;
    std::mutex mutex_;
};

} // namespace resources
