/*********************************************************************
 * \file   AssetLibrary.cpp
 *
 * \author Romain BOULLARD
 * \date   July 2026
 *********************************************************************/
#include <Engine/Asset/AssetLibrary.hpp>

#include <AssetsForTesting/Asset/AssetA.hpp>
#include <AssetsForTesting/Asset/AssetB.hpp>
#include <AssetsForTesting/Asset/AssetC.hpp>
#include <gtest/gtest.h>

namespace Bigfoot
{
class AssetLibraryFixture: public ::testing::Test
{
  protected:
    AssetContainer<AssetA> m_containerA;
    AssetContainer<AssetB> m_containerB;
    AssetContainer<AssetC> m_containerC;

    AssetLibrary m_library;
};

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

TEST_F(AssetLibraryFixture, Insert_ShouldReturnTrueOnSuccess)
{
    EXPECT_TRUE(m_library.Insert(&m_containerA));
    EXPECT_TRUE(m_library.Insert(&m_containerB));
    EXPECT_TRUE(m_library.Insert(&m_containerC));
}

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

TEST_F(AssetLibraryFixture, Insert_ShouldReturnFalseOnDuplicate)
{
    std::ignore = m_library.Insert(&m_containerA);
    EXPECT_FALSE(m_library.Insert(&m_containerA));

    AssetContainer<AssetA> m_containerAA;
    EXPECT_FALSE(m_library.Insert(&m_containerAA));
}

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

TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnTheAssetContainerIfAvailable)
{
    std::ignore = m_library.Insert(&m_containerA);
    std::ignore = m_library.Insert(&m_containerB);
    std::ignore = m_library.Insert(&m_containerC);

    EXPECT_EQ(m_library.GetAssetContainer<AssetA>(), &m_containerA);
    EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID<AssetA>()), &m_containerA);
    EXPECT_EQ(m_library.GetAssetContainer<AssetB>(), &m_containerB);
    EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID<AssetB>()), &m_containerB);
    EXPECT_EQ(m_library.GetAssetContainer<AssetC>(), &m_containerC);
    EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID<AssetC>()), &m_containerC);

    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer<AssetA>(), &m_containerA);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer(GetAssetTypeID<AssetA>()), &m_containerA);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer<AssetB>(), &m_containerB);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer(GetAssetTypeID<AssetB>()), &m_containerB);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer<AssetC>(), &m_containerC);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer(GetAssetTypeID<AssetC>()), &m_containerC);
}

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

TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnNullptrIfTheContainerDoesNotExist)
{
    std::ignore = m_library.Insert(&m_containerB);

    EXPECT_EQ(m_library.GetAssetContainer<AssetA>(), nullptr);
    EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID<AssetA>()), nullptr);

    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer<AssetA>(), nullptr);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).GetAssetContainer(GetAssetTypeID<AssetA>()), nullptr);
}

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

TEST_F(AssetLibraryFixture, FindAssetContainerContainerForUUID_ShouldReturnTheAssetContainerIfAvailable)
{
    std::ignore = m_library.Insert(&m_containerA);
    std::ignore = m_library.Insert(&m_containerB);
    std::ignore = m_library.Insert(&m_containerC);

    const SlotMapKey keyA = m_containerA.Insert();
    const SlotMapKey keyB = m_containerB.Insert();
    const SlotMapKey keyC = m_containerC.Insert();

    const UUID uuidA = m_containerA.Get(keyA)->GetHeader().uuid;
    const UUID uuidB = m_containerB.Get(keyB)->GetHeader().uuid;
    const UUID uuidC = m_containerC.Get(keyC)->GetHeader().uuid;

    EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidA), &m_containerA);
    EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidB), &m_containerB);
    EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidC), &m_containerC);

    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).FindAssetContainerContainerForUUID(uuidA), &m_containerA);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).FindAssetContainerContainerForUUID(uuidB), &m_containerB);
    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).FindAssetContainerContainerForUUID(uuidC), &m_containerC);
}

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

TEST_F(AssetLibraryFixture, FindAssetContainerContainerForUUID_ShouldReturnNullptrIfTheContainerDoesNotExist)
{
    std::ignore = m_library.Insert(&m_containerA);
    std::ignore = m_library.Insert(&m_containerB);
    std::ignore = m_library.Insert(&m_containerC);

    std::ignore = m_containerA.Insert();
    std::ignore = m_containerB.Insert();
    std::ignore = m_containerC.Insert();

    EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(UUID {}), nullptr);

    EXPECT_EQ(const_cast<const AssetLibrary&>(m_library).FindAssetContainerContainerForUUID(UUID {}), nullptr);
}

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

TEST_F(AssetLibraryFixture, ScopedActiveAssetLibrary_ShouldChangeTheActiveAssetLibraryInAScopedWay)
{
    EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary);
    {
        ScopedActiveAssetLibrary activeAssetLibraryScoped {&m_library};
        EXPECT_EQ(g_activeAssetLibrary, &m_library);
    }
    EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary);
}
}   // namespace Bigfoot
