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

using namespace TwitchInGames;
using namespace Utilities;

namespace {
	string_t const currentBio= _T("T-W-I-G real bio from API");
	string_t const updatedBio= _T("T-W-I-G real updated bio from API");

	bool IsServerFailure(int responseCode) {
		return responseCode >= 500 && responseCode < 600;
	}
}

TEST(UserTest, FetchCurrentUser_Success) {
	try {
		auto user= User::FetchCurrent(clientId, token).get();
		EXPECT_EQ(user.BroadcasterType, _T(""));
		if(user.Description != currentBio) {
			Utilities::WriteWarning("ignoring user description mis-match; test incomplete");
		}
		EXPECT_EQ(user.DisplayName, _T("TwIGgIEg"));
		EXPECT_EQ(user.Email, _T("loohill@twitch.tv"));
		EXPECT_EQ(user.Login, _T("twiggieg"));
		EXPECT_EQ(user.OfflineImageUrl, _T(""));
		EXPECT_EQ(user.ProfileImageUrl, _T("https://static-cdn.jtvnw.net/jtv_user_pictures/f5955ee4e093f0c0-profile_image-300x300.png"));
		EXPECT_EQ(user.Type, _T(""));
		EXPECT_EQ(user.Id, userId);
		EXPECT_GE(user.ViewCount, 1u);
		auto data= user.FetchProfileImage().get();
		EXPECT_EQ(data.size(), 62086u);
		data= user.FetchOfflineImage().get();
		EXPECT_EQ(data.size(), 38234u);
	} catch(TwitchException const& ex) {
		if(ex.ErrorCode == 400) {
			Utilities::WriteWarning("ignoring user authentication error; test incomplete");
		} else {
			throw;
		}
	}
}

TEST(UserTest, FetchCurrentUser_Failure) {
	auto task= User::FetchCurrent(clientId, token_Invalid);
	EXPECT_ANY_THROW(task.get());
}

TEST(UserTest, FetchOtherUserByLogin_Success) {
	auto user= User::FetchOtherByLogin(clientId_NoOAuth, login).get();
	EXPECT_EQ(user.BroadcasterType, _T(""));
	if(user.Description != currentBio) {
		Utilities::WriteWarning("ignoring user description mis-match; test incomplete");
	}
	EXPECT_EQ(user.DisplayName, _T("TwIGgIEg"));
	EXPECT_EQ(user.Email, _T(""));
	EXPECT_NE(user.Email, _T("loohill@twitch.tv"));
	EXPECT_EQ(user.Login, _T("twiggieg"));
	EXPECT_EQ(user.OfflineImageUrl, _T(""));
	EXPECT_EQ(user.ProfileImageUrl, _T("https://static-cdn.jtvnw.net/jtv_user_pictures/f5955ee4e093f0c0-profile_image-300x300.png"));
	EXPECT_EQ(user.Type, _T(""));
	EXPECT_EQ(user.Id, userId);
	EXPECT_GE(user.ViewCount, 1u);

	auto userUpper = User::FetchOtherByLogin(clientId_NoOAuth, loginUpper).get();
	EXPECT_EQ(userUpper.BroadcasterType, _T(""));
	if (userUpper.Description != currentBio) {
		Utilities::WriteWarning("ignoring user description mis-match; test incomplete");
	}
	EXPECT_EQ(userUpper.DisplayName, _T("TwIGgIEg"));
	EXPECT_EQ(userUpper.Email, _T(""));
	EXPECT_NE(userUpper.Email, _T("loohill@twitch.tv"));
	EXPECT_EQ(userUpper.Login, _T("twiggieg"));
	EXPECT_EQ(userUpper.OfflineImageUrl, _T(""));
	EXPECT_EQ(userUpper.ProfileImageUrl, _T("https://static-cdn.jtvnw.net/jtv_user_pictures/f5955ee4e093f0c0-profile_image-300x300.png"));
	EXPECT_EQ(userUpper.Type, _T(""));
	EXPECT_EQ(userUpper.Id, userId);
	EXPECT_GE(userUpper.ViewCount, 1u);
}

TEST(UserTest, FetchOtherUserById_Success) {
	auto user= User::FetchOtherById(clientId_NoOAuth, userId).get();
	EXPECT_EQ(user.BroadcasterType, _T(""));
	if(user.Description != currentBio) {
		Utilities::WriteWarning("ignoring user description mis-match; test incomplete");
	}
	EXPECT_EQ(user.DisplayName, _T("TwIGgIEg"));
	EXPECT_EQ(user.Email, _T(""));
	EXPECT_NE(user.Email, _T("loohill@twitch.tv"));
	EXPECT_EQ(user.Login, _T("twiggieg"));
	EXPECT_EQ(user.OfflineImageUrl, _T(""));
	EXPECT_EQ(user.ProfileImageUrl, _T("https://static-cdn.jtvnw.net/jtv_user_pictures/f5955ee4e093f0c0-profile_image-300x300.png"));
	EXPECT_EQ(user.Type, _T(""));
	EXPECT_EQ(user.Id, userId);
	EXPECT_GE(user.ViewCount, 1u);
}

TEST(UserTest, FetchOtherUserByLogin_Failure) {
	auto task= User::FetchOtherByLogin(clientId_NoOAuth, login_Invalid);
	EXPECT_ANY_THROW(task.get());
}

TEST(UserTest, FetchOtherUserById_Failure) {
	auto task= User::FetchOtherById(clientId_NoOAuth, userId_Invalid);
	EXPECT_ANY_THROW(task.get());
}

TEST(UserTest, FetchUserProfileImage_NoImage_Failure) {
	// This test hacks the user's profile image with a non-existent one.
	User user;
	auto* p= reinterpret_cast<tstring*>(&user);
	(p + 7)->assign(_T("https://static-cdn.jtvnw.net/jtv_user_pictures/f5955ee4e093f0c0-profile_image-457x219.png"));
	auto data= user.FetchProfileImage().get();
	EXPECT_EQ(data.size(), 6293u);
}

TEST(UserTest, FetchUserProfileImage_InvalidUrl_Failure) {
	// This test hacks the user's profile image with an invalid one.
	User user;
	auto* p= reinterpret_cast<tstring*>(&user);
	(p + 7)->assign(_T("invalid:url"));
	auto task= user.FetchProfileImage();
	EXPECT_ANY_THROW(task.get());
}

TEST(UserTest, UpdateUserDescription_Success) {
	try {
		auto user= User::FetchCurrent(clientId, token).get();
		user.UpdateDescription(clientId, token, updatedBio).get();
		user= User::FetchCurrent(clientId, token).get();
		EXPECT_EQ(user.Description, updatedBio);
		user.UpdateDescription(clientId, token, currentBio).get();
	} catch(TwitchException const& ex) {
		if(ex.ErrorCode == 400) {
			Utilities::WriteWarning("ignoring user authentication error; test incomplete");
		} else if(IsServerFailure(ex.ErrorCode)) {
			Utilities::WriteWarning("ignoring server failure; test incomplete");
		} else {
			throw;
		}
	}
}

TEST(UserTest, GetFollowers_Success) {
	// This user has over two million followers.
	tstring popularUserId= _T("23161357");

	// Get the first page, default size, of followers.  Include a token.
	FollowersRequest request;
	auto response= request.Fetch(clientId, token, popularUserId).get();
	EXPECT_GE(response.TotalCount, 2'000'000u);
	auto firstUserId= response.Followers.front().UserId;

	// Get the next page, larger size, of followers.  Don't include a token.
	request.Count= 30;
	request.Cursor= response.Cursor;
	request.Direction= FollowersRequest::PaginationDirection::Forward;
	response= request.Fetch(clientId, tstring(), popularUserId).get();
	EXPECT_EQ(response.Followers.size(), request.Count);
	EXPECT_GE(response.TotalCount, 2'000'000u);
	EXPECT_NE(response.Followers.front().UserId, firstUserId);
}

TEST(UserTest, CreateClip_Failure) {
	auto task= Clip::Create(clientId, token, userId);
	int resultCode= 0;
	try {
		task.get();
	} catch(TwitchException const& ex) {
		resultCode= ex.ErrorCode;
	}
	EXPECT_EQ(resultCode, 404);
}
