#pragma once

#include <string>
#include <unordered_map>
#include <memory>
#include <future>
#include <yaml-cpp/yaml.h>
#include "../types/vec2.h"
#include <GL/glew.h>
#include "miniaudio.h"

enum class AssetType { Image, Audio };

struct AssetInfo
{
    uint64_t uaid = 0;
    std::string path;
    std::string filename;
    std::string filetype;
    AssetType type = AssetType::Image;
    std::string hash;
    std::time_t lastModified = 0;
    bool loaded = false;

    virtual ~AssetInfo() = default;

    virtual void Save(YAML::Emitter& out) const = 0;
    virtual void Load(const YAML::Node& node) = 0;
};

struct ImageAssetInfo : public AssetInfo
{
    core::types::Vec2 size = {0, 0};
    int channels = 4;
    std::string format = "GL_RGBA";
    GLuint textureID = 0;

    ImageAssetInfo() { type = AssetType::Image; }

    void Save(YAML::Emitter& out) const override;
    void Load(const YAML::Node& node) override;
};

struct AudioAssetInfo : public AssetInfo
{
    ma_sound* sound = nullptr;

    AudioAssetInfo() { type = AssetType::Audio; }

    void Save(YAML::Emitter& out) const override;
    void Load(const YAML::Node& node) override;
};

const char* MiniaudioResultToString(ma_result result);


class AssetManager
{
public:
    static void Init();
    static void LoadAssetAsync(const std::string& path, AssetType type);
    static const AssetInfo* GetAssetByID(uint64_t uaid);
    static const AssetInfo* GetAssetByPath(const std::string& path);
    static const std::unordered_map<uint64_t, std::shared_ptr<AssetInfo>>& GetAllAssets();
    static void UnloadAsset(uint64_t uaid);
    static void ClearAllAssets();
    static void Save(YAML::Emitter& out);
    static void Load(const YAML::Node& node);

private:
    static std::unordered_map<uint64_t, std::shared_ptr<AssetInfo>> s_Assets;
    static std::unordered_map<std::string, uint64_t> s_PathToUAID;
    static uint64_t s_NextUAID;

    static uint64_t GenerateUAID();
    static void LoadImageInternal(const std::string& path, uint64_t uaid);
    static void LoadAudioInternal(const std::string& path, uint64_t uaid);
};
