/*
 * Copyright © 2021-2026 Pierrick Caillon <pierrick.caillon+zipdirfs@megami.fr>
 */
#include "ChangedStart.h"
#include "test/gtest.h"
#include <filesystem>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

namespace Test::ZipDirFs::Components
{
	namespace fs = std::filesystem;
	using ::testing::Return;
	using ::ZipDirFs::Components::ChangedProxy;
	using ::ZipDirFs::Components::ChangedStart;

	namespace
	{
		struct ChangedMock : public ::ZipDirFs::Containers::Helpers::Changed
		{
			MOCK_METHOD0(changed, bool());
			MOCK_CONST_METHOD0(time, FileTime());
			bool operator()() { return changed(); }
			operator FileTime() const { return time(); }
		};
	} // namespace

	TEST(ChangedStartTest, Init)
	{
		auto timeF{[]() -> ::ZipDirFs::Utilities::FileTime { return ::ZipDirFs::Utilities::FileTime{}; }};
		auto buildRealF{[]() -> std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed> {
			return std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
				std::unique_ptr<ChangedMock>());
		}};
		ChangedStart* changedStart;
		std::shared_ptr<ChangedProxy> proxy(new ChangedProxy(
			std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(std::unique_ptr<ChangedStart>(
				changedStart = new ChangedStart(std::move(timeF), std::move(buildRealF), proxy)))));
		EXPECT_EQ(ChangedStartAccess::get_lastChanged(*changedStart), ::ZipDirFs::Utilities::FileTime{});
		EXPECT_EQ(ChangedStartAccess::get_called(*changedStart), false);
	}

	TEST(ChangedStartTest, ChangedFalse)
	{
		std::unique_ptr<ChangedMock> changedMock(new ChangedMock());
		EXPECT_CALL(*changedMock, changed()).WillOnce(Return(false));
		std::shared_ptr<ChangedProxy> proxy(
			new ChangedProxy(std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
				std::unique_ptr<ChangedStart>(new ChangedStart([]() -> ::ZipDirFs::Utilities::FileTime {
					return ::ZipDirFs::Utilities::FileTime{};
				},
					[&changedMock]() -> std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed> {
						return std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
							std::move(changedMock));
					},
					proxy)))));
		EXPECT_EQ((*proxy)(), false);
		EXPECT_EQ(changedMock, nullptr);
	}

	TEST(ChangedStartTest, ChangedTrue)
	{
		std::unique_ptr<ChangedMock> changedMock(new ChangedMock());
		EXPECT_CALL(*changedMock, changed()).WillOnce(Return(true));
		std::shared_ptr<ChangedProxy> proxy(
			new ChangedProxy(std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
				std::unique_ptr<ChangedStart>(new ChangedStart([]() -> ::ZipDirFs::Utilities::FileTime {
					return ::ZipDirFs::Utilities::FileTime{};
				},
					[&changedMock]() -> std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed> {
						return std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
							std::move(changedMock));
					},
					proxy)))));
		EXPECT_EQ((*proxy)(), true);
		EXPECT_EQ(changedMock, nullptr);
	}

	TEST(ChangedStartTest, TimeFirst)
	{
		const fs::file_time_type expected(::Test::randomFileTime());
		ChangedStart* changedStart;
		std::shared_ptr<ChangedProxy> proxy(new ChangedProxy(
			std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(std::unique_ptr<ChangedStart>(
				changedStart = new ChangedStart(
					[expected]() -> ::ZipDirFs::Utilities::FileTime { return expected; },
					[]() -> std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed> {
						return std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
							std::unique_ptr<ChangedMock>());
					},
					proxy)))));
		EXPECT_EQ(ChangedStart::FileTime{*proxy}, expected);
		EXPECT_EQ(ChangedStartAccess::get_lastChanged(*changedStart), expected);
		EXPECT_EQ(ChangedStartAccess::get_called(*changedStart), true);
	}

	TEST(ChangedStartTest, TimeOther)
	{
		const fs::file_time_type expected(::Test::randomFileTime());
		const fs::file_time_type other(::Test::randomFileTimeDifferentFrom(expected));
		ChangedStart* changedStart;
		std::shared_ptr<ChangedProxy> proxy(new ChangedProxy(
			std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(std::unique_ptr<ChangedStart>(
				changedStart = new ChangedStart(
					[other]() -> ::ZipDirFs::Utilities::FileTime { return other; },
					[]() -> std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed> {
						return std::unique_ptr<::ZipDirFs::Containers::Helpers::Changed>(
							std::unique_ptr<ChangedMock>());
					},
					proxy)))));
		ChangedStartAccess::set_lastChanged(*changedStart, expected);
		ChangedStartAccess::set_called(*changedStart, true);
		EXPECT_EQ(ChangedStart::FileTime{*proxy}, expected);
	}
} // namespace Test::ZipDirFs::Components
