#include "AssetManager.h"
#include <yaml-cpp/yaml.h>
#include "assets/Texture2D.h"
#include "Logger.h"
#include "Profiler.h"

namespace fs = std::filesystem;

namespace OX {

std::unordered_map<std::string, std::shared_ptr<Asset>> AssetManager::s_AssetMap;
std::unordered_map<std::string, std::type_index> AssetManager::s_AssetTypes;
std::unordered_map<std::string, AssetManager::AssetMetadata> AssetManager::s_AssetDatabase;

std::mutex AssetManager::s_QueueMutex;
std::queue<std::pair<std::string, AssetManager::AssetMetadata>> AssetManager::s_LoadQueue;

std::thread AssetManager::s_BackgroundThread;
std::atomic<bool> AssetManager::s_Running = false;

fs::path AssetManager::s_ProjectDirectory;

void AssetManager::Init(const std::string& projectDir) {
    OX_PROFILE_FUNCTION();
    s_ProjectDirectory = fs::absolute(projectDir);
    s_Running = true;
    s_BackgroundThread = std::thread([] {
        ScanAssetsRecursive(s_ProjectDirectory);
    });
}

void AssetManager::Shutdown() {
    OX_PROFILE_FUNCTION();
    s_Running = false;
    if (s_BackgroundThread.joinable())
        s_BackgroundThread.join();
}

void AssetManager::ScanAssetsRecursive(const fs::path& root) {
    OX_PROFILE_FUNCTION();
    for (auto& entry : fs::recursive_directory_iterator(root)) {
        if (!entry.is_regular_file()) continue;

        const auto& path = entry.path();
        std::string virtualPath = GetVirtualPath(path);
        std::string type = DetectTypeFromExtension(path);
        if (type.empty()) continue;

        AssetMetadata meta{ type, path.string() };

        std::lock_guard<std::mutex> lock(s_QueueMutex);
        s_LoadQueue.push({ virtualPath, meta });
    }
}

void AssetManager::Tick() {
    OX_PROFILE_FUNCTION();
    std::lock_guard<std::mutex> lock(s_QueueMutex);
    if (!s_LoadQueue.empty()) {
        auto [id, meta] = s_LoadQueue.front();
        s_LoadQueue.pop();
        RegisterAssetMetadata(id, meta.type, meta.path);
        LoadAsset(id);
    }
}

std::string AssetManager::GetVirtualPath(const fs::path& absolute) {
    OX_PROFILE_FUNCTION();
    fs::path relative = fs::relative(absolute, s_ProjectDirectory);
    return "res://" + relative.generic_string();
}

std::string AssetManager::DetectTypeFromExtension(const fs::path& path) {
    OX_PROFILE_FUNCTION();
    std::string ext = path.extension().string();
    if (ext == ".png" || ext == ".jpg") return "texture2D";
    if (ext == ".wav" || ext == ".ogg") return "audio";
    if (ext == ".prefab" || ext == ".yaml") return "prefab";
    return "";
}

void AssetManager::RegisterAssetMetadata(const std::string& id, const std::string& type, const std::string& path) {
    OX_PROFILE_FUNCTION();
    s_AssetDatabase[id] = { type, path };
}

bool AssetManager::LoadAsset(const std::string& id) {
    OX_PROFILE_FUNCTION();
    auto it = s_AssetDatabase.find(id);
    if (it == s_AssetDatabase.end()) return false;

    const auto& meta = it->second;
    std::shared_ptr<Asset> asset;

    if (meta.type == "texture2D")
        asset = std::make_shared<Texture2D>();


    if (asset && asset->LoadFromFile(meta.path)) {
        s_AssetMap[id] = asset;
        s_AssetTypes.emplace(id, std::type_index(typeid(*asset)));
        Logger::LogInfo("Loaded asset '%s' (%s)", id.c_str(), meta.path.c_str());
        return true;
    }

    Logger::LogError("Failed to load asset '%s'", id.c_str());
    return false;
}

} // namespace OX
