/*********************************************************************
 * \file   Asset.hpp
 *
 * \author Romain BOULLARD
 * \date   April 2026
 *********************************************************************/
#ifndef BIGFOOT_ENGINE_ASSET_HPP
#define BIGFOOT_ENGINE_ASSET_HPP
#include <Engine/BigFile/Asset/Asset_generated.hpp>

#include <EASTL/vector.h>
#include <rapidhash.h>

namespace Bigfoot
{
template<class FLAT_ASSET>
class Asset
{
  public:
    Asset()
    {
        m_header.type_id = GetTypeID();
        m_header.type_name = GetTypeName();
    }

    explicit Asset(const eastl::span<const std::byte> p_flatbuffer):
        m_header(UnPackHeader(p_flatbuffer)),
        m_asset(UnpackAsset(p_flatbuffer))
    {
    }

    const Bigfoot::Flat::AssetHeaderT& GetHeader() const
    {
        return m_header;
    }

    const typename FLAT_ASSET::NativeTableType& GetAsset() const
    {
        return m_asset;
    }

    typename FLAT_ASSET::NativeTableType& GetAsset()
    {
        return m_asset;
    }

    eastl::vector<std::byte> Pack() const
    {
        flatbuffers::FlatBufferBuilder assetFbb;
        assetFbb.Finish(FLAT_ASSET::Pack(assetFbb, &m_asset));

        Flat::AssetT outer;
        outer.header = eastl::make_unique<Flat::AssetHeaderT>(m_header);
        outer.asset = {assetFbb.GetBufferSpan().begin(), assetFbb.GetBufferSpan().end()};

        flatbuffers::FlatBufferBuilder fullFbb;
        fullFbb.Finish(Flat::Asset::Pack(fullFbb, &outer));

        return eastl::vector<std::byte> {std::bit_cast<std::byte*>(fullFbb.GetBufferPointer()),
                                         std::bit_cast<std::byte*>(fullFbb.GetBufferPointer() + fullFbb.GetSize())};
    }

    void SetName(const eastl::string_view p_name)
    {
        m_header.name = p_name;
    }

    void SetVersion(const std::uint32_t p_version)
    {
        m_header.version = p_version;
    }

    static std::uint64_t GetTypeID()
    {
        static const std::uint64_t typeID = rapidhash(FLAT_ASSET::GetFullyQualifiedName(),
                                                      std::strlen(FLAT_ASSET::GetFullyQualifiedName()));
        return typeID;
    }

    static eastl::string_view GetTypeName()
    {
        return FLAT_ASSET::GetFullyQualifiedName();
    }

  private:
    static Bigfoot::Flat::AssetHeaderT UnPackHeader(const eastl::span<const std::byte> p_flatbuffer)
    {
        Bigfoot::Flat::AssetHeaderT header;

        flatbuffers::GetRoot<Flat::Asset>(p_flatbuffer.data())->header()->UnPackTo(&header);

        return header;
    }

    static typename FLAT_ASSET::NativeTableType UnpackAsset(const eastl::span<const std::byte> p_flatbuffer)
    {
        typename FLAT_ASSET::NativeTableType asset;

        const Flat::Asset* outer = flatbuffers::GetRoot<Flat::Asset>(p_flatbuffer.data());
        flatbuffers::GetRoot<FLAT_ASSET>(outer->asset()->data())->UnPackTo(&asset, nullptr);

        return asset;
    }

  private:
    Flat::AssetHeaderT m_header;
    typename FLAT_ASSET::NativeTableType m_asset;
};
}   // namespace Bigfoot

#endif
