/*********************************************************************
 * \file   BigFile.cpp
 *
 * \author Romain BOULLARD
 * \date   December 2025
 *********************************************************************/
#include <Engine/Asset/Asset.hpp>

#include <Engine/EngineLogger_generated.hpp>

#include <System/Log/Log.hpp>

#include <Utils/Singleton.hpp>
#include <Utils/TargetMacros.h>

#include <EngineTests/Asset/AssetA.hpp>
#include <EngineTests/Asset/AssetB.hpp>
#include <EngineTests/Asset/AssetC.hpp>

#include <gtest/gtest.h>

namespace Bigfoot
{
class AssetFixture: public ::testing::Test
{
  protected:
    void SetUp() override
    {
        BIGFOOT_NOT_OPTIMIZED_ONLY(std::ignore = Singleton<Log>::Instance().RegisterLogger(ENGINE_LOGGER);)
    }

    BIGFOOT_NOT_OPTIMIZED_ONLY(Singleton<Log>::Lifetime m_loggerLifetime;)
};

/****************************************************************************************/

TEST_F(AssetFixture, AssetATests)
{
    constexpr eastl::string_view name = "Hello";
    constexpr std::uint32_t version = 42;
    constexpr std::uint32_t health = 100;
    constexpr std::uint32_t mana = 50;

    AssetA assetA;
    assetA.SetName(name);
    assetA.SetVersion(version);
    assetA.GetAsset().health = health;
    assetA.GetAsset().mana = mana;

    const eastl::vector<std::byte> test = assetA.Save();

    AssetA assetA_dup {test};

    EXPECT_EQ(assetA.GetHeader().uuid, assetA_dup.GetHeader().uuid);

    EXPECT_EQ(assetA.GetHeader().type_id, AssetA::GetTypeID());
    EXPECT_EQ(assetA.GetHeader().type_id, assetA_dup.GetHeader().type_id);

    EXPECT_EQ(assetA.GetHeader().type_name, AssetA::GetTypeName());
    EXPECT_EQ(assetA.GetHeader().type_name, assetA_dup.GetHeader().type_name);

    EXPECT_EQ(assetA.GetHeader().name, name);
    EXPECT_EQ(assetA.GetHeader().name, assetA_dup.GetHeader().name);

    EXPECT_EQ(assetA.GetHeader().version, version);
    EXPECT_EQ(assetA.GetHeader().version, assetA_dup.GetHeader().version);

    EXPECT_EQ(assetA.GetAsset().health, health);
    EXPECT_EQ(assetA.GetAsset().health, assetA_dup.GetAsset().health);

    EXPECT_EQ(assetA.GetAsset().mana, mana);
    EXPECT_EQ(assetA.GetAsset().mana, assetA_dup.GetAsset().mana);
}

/****************************************************************************************/

TEST_F(AssetFixture, AssetBTests)
{
    constexpr eastl::string_view nameA = "Hello";
    constexpr std::uint32_t versionA = 42;
    constexpr std::uint32_t healthA = 100;
    constexpr std::uint32_t manaA = 50;

    AssetA assetA;
    assetA.SetName(nameA);
    assetA.SetVersion(versionA);
    assetA.GetAsset().health = healthA;
    assetA.GetAsset().mana = manaA;

    constexpr eastl::string_view nameAA = "There";
    constexpr std::uint32_t versionAA = 42;
    constexpr std::uint32_t healthAA = 100;
    constexpr std::uint32_t manaAA = 50;

    AssetA assetAA;
    assetAA.SetName(nameAA);
    assetAA.SetVersion(versionAA);
    assetAA.GetAsset().health = healthAA;
    assetAA.GetAsset().mana = manaAA;

    constexpr eastl::string_view nameB = "Kenobi";
    constexpr std::uint32_t versionB = 1;

    AssetB assetB;
    assetB.SetName(nameB);
    assetB.SetVersion(versionB);
    assetB.GetAsset().asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
    assetB.GetAsset().asset_a_refs = {SoftReference<AssetA> {assetA.GetHeader().uuid},
                                      SoftReference<AssetA> {assetAA.GetHeader().uuid}};

    const eastl::vector<std::byte> test = assetB.Save();

    AssetB assetB_dup {test};

    EXPECT_EQ(assetB.GetHeader().uuid, assetB_dup.GetHeader().uuid);

    EXPECT_EQ(assetB.GetHeader().type_id, AssetB::GetTypeID());
    EXPECT_EQ(assetB.GetHeader().type_id, assetB_dup.GetHeader().type_id);

    EXPECT_EQ(assetB.GetHeader().type_name, AssetB::GetTypeName());
    EXPECT_EQ(assetB.GetHeader().type_name, assetB_dup.GetHeader().type_name);

    EXPECT_EQ(assetB.GetHeader().name, nameB);
    EXPECT_EQ(assetB.GetHeader().name, assetB_dup.GetHeader().name);

    EXPECT_EQ(assetB.GetHeader().version, versionB);
    EXPECT_EQ(assetB.GetHeader().version, assetB_dup.GetHeader().version);

    EXPECT_EQ(assetB.GetAsset().asset_a_ref, HardReference<AssetA> {assetA.GetHeader().uuid});
    EXPECT_EQ(assetB.GetAsset().asset_a_ref, assetB_dup.GetAsset().asset_a_ref);

    EXPECT_EQ(assetB.GetAsset().asset_a_refs,
              (eastl::vector<SoftReference<AssetA>> {SoftReference<AssetA> {assetA.GetHeader().uuid},
                                                     SoftReference<AssetA> {assetAA.GetHeader().uuid}}));
    EXPECT_EQ(assetB.GetAsset().asset_a_refs, assetB_dup.GetAsset().asset_a_refs);
}

/****************************************************************************************/

TEST_F(AssetFixture, AssetCTests)
{
    constexpr eastl::string_view nameA = "Hello";
    constexpr std::uint32_t versionA = 42;
    constexpr std::uint32_t healthA = 100;
    constexpr std::uint32_t manaA = 50;

    AssetA assetA;
    assetA.SetName(nameA);
    assetA.SetVersion(versionA);
    assetA.GetAsset().health = healthA;
    assetA.GetAsset().mana = manaA;

    constexpr eastl::string_view nameAA = "There";
    constexpr std::uint32_t versionAA = 42;
    constexpr std::uint32_t healthAA = 100;
    constexpr std::uint32_t manaAA = 50;

    AssetA assetAA;
    assetAA.SetName(nameAA);
    assetAA.SetVersion(versionAA);
    assetAA.GetAsset().health = healthAA;
    assetAA.GetAsset().mana = manaAA;

    constexpr eastl::string_view nameB = "Kenobi";
    constexpr std::uint32_t versionB = 1;

    AssetB assetB;
    assetB.SetName(nameB);
    assetB.SetVersion(versionB);
    assetB.GetAsset().asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
    assetB.GetAsset().asset_a_refs = {SoftReference<AssetA> {assetA.GetHeader().uuid},
                                      SoftReference<AssetA> {assetAA.GetHeader().uuid}};

    constexpr eastl::string_view nameC = "General";
    constexpr std::uint32_t versionC = 1;

    AssetC assetC;
    assetC.SetName(nameC);
    assetC.SetVersion(versionC);
    assetC.GetAsset().inner_table->asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
    assetC.GetAsset().inner_table->asset_a_refs = {HardReference<AssetA> {assetA.GetHeader().uuid},
                                                   HardReference<AssetA> {assetAA.GetHeader().uuid}};
    assetC.GetAsset().asset_b_ref = HardReference<AssetB> {assetB.GetHeader().uuid};
    assetC.GetAsset().asset_b_refs = {SoftReference<AssetB> {assetB.GetHeader().uuid}};

    const eastl::vector<std::byte> test = assetC.Save();

    AssetC assetC_dup {test};

    EXPECT_EQ(assetC.GetHeader().uuid, assetC_dup.GetHeader().uuid);

    EXPECT_EQ(assetC.GetHeader().type_id, AssetC::GetTypeID());
    EXPECT_EQ(assetC.GetHeader().type_id, assetC_dup.GetHeader().type_id);

    EXPECT_EQ(assetC.GetHeader().type_name, AssetC::GetTypeName());
    EXPECT_EQ(assetC.GetHeader().type_name, assetC_dup.GetHeader().type_name);

    EXPECT_EQ(assetC.GetHeader().name, nameC);
    EXPECT_EQ(assetC.GetHeader().name, assetC_dup.GetHeader().name);

    EXPECT_EQ(assetC.GetHeader().version, versionC);
    EXPECT_EQ(assetC.GetHeader().version, assetC_dup.GetHeader().version);

    EXPECT_EQ(assetC.GetAsset().asset_b_ref, HardReference<AssetB> {assetB.GetHeader().uuid});
    EXPECT_EQ(assetC.GetAsset().asset_b_ref, assetC_dup.GetAsset().asset_b_ref);

    EXPECT_EQ(assetC.GetAsset().asset_b_refs,
              (eastl::vector<SoftReference<AssetB>> {SoftReference<AssetB> {assetB.GetHeader().uuid}}));
    EXPECT_EQ(assetC.GetAsset().asset_b_refs, assetC_dup.GetAsset().asset_b_refs);

    EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_ref, HardReference<AssetA> {assetA.GetHeader().uuid});
    EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_ref, assetC_dup.GetAsset().inner_table->asset_a_ref);

    EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_refs,
              (eastl::vector<HardReference<AssetA>> {HardReference<AssetA> {assetA.GetHeader().uuid},
                                                     HardReference<AssetA> {assetAA.GetHeader().uuid}}));
    EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_refs, assetC_dup.GetAsset().inner_table->asset_a_refs);
}
}   // namespace Bigfoot
