/*********************************************************************
 * \file   AssetContainer.hpp
 *
 * \author Romain BOULLARD
 * \date   May 2026
 *********************************************************************/
#ifndef BIGFOOT_ENGINE_ASSETCONTAINER_HPP
#define BIGFOOT_ENGINE_ASSETCONTAINER_HPP
#include <Engine/EngineAssertHandler.hpp>

#include <System/UUID/UUID.hpp>

#include <ankerl/unordered_dense.h>

#include <cstdint>

namespace Bigfoot
{
template<class ASSET>
class AssetContainer
{
  public:
    AssetContainer()
    {
        CRITICAL_ASSERT(EngineAssertHandler, !ms_instance, "Asset container already exists!");
        ms_instance = this;
    }

    AssetContainer(const AssetContainer&) = delete;
    AssetContainer& operator=(const AssetContainer&) = delete;

    ~AssetContainer()
    {
        ms_instance = nullptr;
    }

    struct Entry
    {
        std::uint32_t m_hardRefCount = 0;
        std::uint32_t m_softRefCount = 0;
    };

    void IncrementHardRefCount(const UUID& p_uuid)
    {
        ++m_entries[p_uuid].m_hardRefCount;
    }

    void DecrementHardRefCount(const UUID& p_uuid)
    {
        if (const auto entry = m_entries.find(p_uuid); entry != m_entries.end())
        {
            CRITICAL_ASSERT(
                EngineAssertHandler,
                entry->second.m_hardRefCount > 0,
                "Double release detected! Decrementing a hard reference to an asset that already does not have any "
                "more hardrefs");
            --entry->second.m_hardRefCount;
        }
    }

    void IncrementSoftRefCount(const UUID& p_uuid)
    {
        ++m_entries[p_uuid].m_softRefCount;
    }

    void DecrementSoftRefCount(const UUID& p_uuid)
    {
        if (const auto entry = m_entries.find(p_uuid); entry != m_entries.end())
        {
            CRITICAL_ASSERT(
                EngineAssertHandler,
                entry->second.m_softRefCount > 0,
                "Double release detected! Decrementing a soft reference to an asset that already does not have any "
                "more softrefs");
            --entry->second.m_softRefCount;
        }
    }

    [[nodiscard]]
    std::uint32_t HardRefCount(const UUID& p_uuid) const
    {
        const auto entry = m_entries.find(p_uuid);
        return entry != m_entries.end() ? entry->second.m_hardRefCount : 0;
    }

    [[nodiscard]]
    std::uint32_t SoftRefCount(const UUID& p_uuid) const
    {
        const auto entry = m_entries.find(p_uuid);
        return entry != m_entries.end() ? entry->second.m_softRefCount : 0;
    }

    [[nodiscard]]
    static AssetContainer& Get()
    {
        return *ms_instance;
    }

  private:
    ankerl::unordered_dense::segmented_map<UUID, Entry> m_entries;

    inline static constinit AssetContainer* ms_instance = nullptr;
};
}   // namespace Bigfoot

#endif
