#include "pch.h"
#include "../../lib/Shared/Internal.h"
#include "Utilities.h"
#ifndef GTEST_OS_WINDOWS
# include "ChatTest.h"
#endif

using namespace TwitchInGames;
using namespace Utilities;

namespace {
	tstring const expectLogin = login;
	auto const nullCallback = [](Chat::Channel&, tstring const&, tstring const&) {};
}

TEST(ChatTest, SingleUser_Success) {
	Chat chat(clientId, token);

	EXPECT_EQ(chat.Login, expectLogin);

	auto channel = chat.JoinChannel(channelName, nullCallback).get();
	auto channels = chat.GetChannels();
	EXPECT_EQ(channels.size(), 1u);
	EXPECT_TRUE(std::find(channels.cbegin(), channels.cend(), channel) != channels.end());
	channels.clear();

	channel->SendLine(_T("[SingleUser] Testing is so hard BabyRage")).get();
	channel->SendLine(_T("[SingleUser] Won't have any receive message PogChamp")).get();

	channel->Depart().get();
	channels = chat.GetChannels();
	EXPECT_EQ(channels.size(), 0u);
}

TEST(ChatTest, SingleUser_UpperCase_Success) {
	Chat chat(clientId, token);
	EXPECT_EQ(chat.Login, expectLogin);

	auto channel = chat.JoinChannel(loginUpper, nullCallback).get();
	auto channels = chat.GetChannels();
	EXPECT_EQ(channels.size(), 1u);
	EXPECT_TRUE(std::find(channels.cbegin(), channels.cend(), channel) != channels.end());
	channels.clear();

	channel->SendLine(_T("[SingleUser_UpperCase] Testing is so hard BabyRage")).get();
	channel->SendLine(_T("[SingleUser_UpperCase] Won't have any receive message PogChamp")).get();

	channel->Depart().get();
	channels = chat.GetChannels();
	EXPECT_EQ(channels.size(), 0u);
}

TEST(ChatTest, SignIn_EmptyInput_Failure) {
	try {
		Chat(_T(""), _T(""));
		EXPECT_FALSE(true);
	} catch(TwitchException const& ex) {
		EXPECT_EQ(ex.ErrorCode, FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
	try {
		Chat(_T(""), token);
		EXPECT_FALSE(true);
	} catch(TwitchException const& ex) {
		EXPECT_EQ(ex.ErrorCode, FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
	try {
		Chat(clientId, _T(""));
		EXPECT_FALSE(true);
	} catch(TwitchException const& ex) {
		EXPECT_EQ(ex.ErrorCode, FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
}

TEST(ChatTest, SignIn_InvalidToken_Failure) {
	try {
		Chat(clientId, _T("abcdefg"));
		EXPECT_FALSE(true);
	} catch(TwitchException const& ex) {
		EXPECT_EQ(ex.ErrorCode, 400);
	}
}

TEST(ChatTest, SignIn_TwiceInDiffChat_Success) {
	Chat chat1(clientId, token);
	EXPECT_EQ(chat1.Login, expectLogin);
	Chat chat2(clientId, token);
	EXPECT_EQ(chat2.Login, expectLogin);
}

TEST(ChatTest, Join_SameChannelTwice_Success) {
	Chat chat(clientId, token);

	auto channel1 = chat.JoinChannel(channelName, nullCallback).get();
	EXPECT_EQ(chat.Channels.size(), 1u);
	auto channel2 = chat.JoinChannel(channelName, nullCallback).get();
	EXPECT_EQ(chat.Channels.size(), 1u); // Already joined; not an error.
	EXPECT_EQ(channel1, channel2);
	channel1.reset(); // Depart the channel.
	EXPECT_EQ(chat.Channels.size(), 1u);
	channel2.reset(); // Depart the channel.
	EXPECT_EQ(chat.Channels.size(), 0u);
	channel1 = chat.JoinChannel(channelName, nullCallback).get();
	EXPECT_EQ(chat.Channels.size(), 1u);
}

TEST(ChatTest, SendMsg_MultiChannel_Success) {
	Chat chat(clientId, token);
	auto channel1 = chat.JoinChannel(channelName, nullCallback).get();
	auto channel2 = chat.JoinChannel(channelName2, nullCallback).get();

	channel1->SendLine(_T("[SendMsg_MultiChannel_Success] Channel ONE")).get();
	channel2->SendLine(_T("[SendMsg_MultiChannel_Success] Channel TWO")).get();
}

TEST(ChatTest, MultiUser_Success) {
	Chat chat1(clientId, token), chat2(clientId, token2);
	auto channel1 = chat1.JoinChannel(channelName, nullCallback).get();

	std::promise<std::tuple<Chat::Channel*, tstring, tstring>> messagePromise;
	auto fn = [&messagePromise](Chat::Channel& channel, tstring const& userName, tstring const& line) {
		messagePromise.set_value(std::make_tuple(&channel, userName, line));
	};
	auto channel2 = chat2.JoinChannel(channelName, fn).get();
	channel1->SendLine(_T("[MultiUser] Kappa Kappa")).get();
	auto messageFuture = messagePromise.get_future();
	if(messageFuture.wait_for(std::chrono::seconds(8)) == std::future_status::ready) {
		auto message = messageFuture.get();
		Chat::Channel* actualChannel;
		tstring actualUserName;
		tstring actualMessage;
		std::tie(actualChannel, actualUserName, actualMessage) = message;
		EXPECT_EQ(actualUserName, channelName);
		EXPECT_EQ(actualChannel, &*channel2);
		EXPECT_EQ(actualMessage, _T("[MultiUser] Kappa Kappa"));
	} else {
		WriteWarning("[MultiUser] message took too long");
	}
}

TEST(ChatTest, MultiUser_SendLong_Success) {
	Chat chat1(clientId, token), chat2(clientId, token2);

	auto channel1 = chat1.JoinChannel(channelName, nullCallback).get();

	std::promise<std::tuple<Chat::Channel*, tstring, tstring>> messagePromise;
	auto fn = [&messagePromise](Chat::Channel& channel, tstring const& userName, tstring const& line) {
		messagePromise.set_value(std::make_tuple(&channel, userName, line));
	};
	auto channel2 = chat2.JoinChannel(channelName, fn).get();
	tstring longMessage(500, _T('l')); // Maximum length is 500 characters (2000 Bytes)
	channel1->SendLine(longMessage.c_str()).get();
	auto messageFuture = messagePromise.get_future();
	if(messageFuture.wait_for(std::chrono::seconds(8)) == std::future_status::ready) {
		auto message = messageFuture.get();
		Chat::Channel* actualChannel;
		tstring actualUserName;
		tstring actualMessage;
		std::tie(actualChannel, actualUserName, actualMessage) = message;
		EXPECT_EQ(actualUserName, channelName);
		EXPECT_EQ(actualChannel, &*channel2);
		EXPECT_EQ(actualMessage, longMessage);
	} else {
		WriteWarning("[MultiUser_SendLong] message took too long");
	}
}
