/*********************************************************************
 * \file   Singleton.cpp
 *
 * \author Romain BOULLARD
 * \date   October 2025
 *********************************************************************/
#include <Utils/Singleton.hpp>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

namespace Bigfoot
{
class SingletonMock
{
  public:
    virtual ~SingletonMock() = default;
    virtual void Construct() = 0;
    virtual void Destruct() = 0;
};

class SingletonTest
{
  public:
    inline static SingletonMock* ms_mock = nullptr;

    explicit SingletonTest(std::uint32_t p_data):
        m_data(p_data)
    {
        if (ms_mock)
        {
            ms_mock->Construct();
        }
    }

    ~SingletonTest()
    {
        if (ms_mock)
        {
            ms_mock->Destruct();
        }
    }

    [[nodiscard]]
    std::uint32_t GetData() const
    {
        return m_data;
    }

  private:
    std::uint32_t m_data;
};

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

class SingletonFixture: public ::testing::Test
{
  protected:
    class SingletonMockImpl: public SingletonMock
    {
      public:
        MOCK_METHOD(void, Construct, (), (override));
        MOCK_METHOD(void, Destruct, (), (override));
    };

    std::unique_ptr<SingletonMockImpl> m_mock;

    void SetUp() override
    {
        m_mock = std::make_unique<::testing::NiceMock<SingletonMockImpl>>();
        SingletonTest::ms_mock = m_mock.get();
    }

    void TearDown() override
    {
        SingletonTest::ms_mock = nullptr;
        m_mock.reset();
    }
};

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

TEST_F(SingletonFixture, ConstructorAndDestructorShouldBeCalled)
{
    ::testing::InSequence seq;

    EXPECT_CALL(*m_mock, Construct()).Times(1);
    EXPECT_CALL(*m_mock, Destruct()).Times(1);

    Singleton<SingletonTest>::Lifetime singleton {42};
}

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

TEST_F(SingletonFixture, GetInstance_ShouldReturnTheInstance)
{
    Singleton<SingletonTest>::Lifetime singleton {42};

    EXPECT_EQ(Singleton<SingletonTest>::GetInstance().GetData(), 42);
}

}   // namespace Bigfoot
