#include "stdafx.h"
#include "TwitchInGames.h"

#pragma comment(lib, "libSceNet_stub_weak.a")

using namespace TwitchInGames;

static void TestClientAuth() {
	ClientAuth clientAuth;
	static string_t const clientId= "dviaxdls39mj44cdnei76mj2dlig33";
	static string_t const redirectUri= "twig://twig.tv/auth";
	auto result= clientAuth.StartAuth(clientId, redirectUri, { "user:read:email" });
	try {
		auto const token= result.get();
		std::cout << "client auth token:  " << token << std::endl;
		auto const user= User::FetchCurrent(clientId, token.c_str()).get();
		auto const emailAddress= user.Email;
		std::cout << "email address:  " << emailAddress << std::endl;
	} catch(TwitchException const& ex) {
		std::cout << "client auth error:  " << ex.what() << std::endl;
	}
}

static void TestServerAuth() {
	// Communicate with the "server" to complete the flow.
	static string_t const clientId= "05zrlud5jr2b73vijreb681r505eox";
	static string_t const hostName= "192.168.43.102";
	tstring token;

	// Create a client socket.
	auto clientSocket= sceNetSocket("connection to server", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_IP);
	if(clientSocket >= 0) {
		// Connect to the "server".
		SceNetSockaddrIn sa{};
		sceNetInetPton(SCE_NET_AF_INET, hostName, &sa.sin_addr);
		sa.sin_family= SCE_NET_AF_INET;
		sa.sin_port= sceNetHtons(50537);
		if(sceNetConnect(clientSocket, reinterpret_cast<SceNetSockaddr*>(&sa), sizeof(sa)) >= 0) {
			// Start the Twitch server authentication flow (flow one).
			ServerAuth serverAuth;
			tstring redirectUri= "http://";
			redirectUri += hostName;
			redirectUri += ":27077/auth";
			tstring state;
			auto authTask= serverAuth.StartAuth(clientId, redirectUri.c_str(), { "user:read:email" }, state);

			// Send the state to the "server".
			sceNetSend(clientSocket, state.data(), state.size() * sizeof(state[0]), 0);
			sceNetShutdown(clientSocket, SCE_NET_SHUT_WR);

			// Receive the access and refresh tokens from the "server".  This
			// might not occur if the user closes the Web browser without
			// signing into Twitch.
			auto const pollId= sceNetEpollCreate("poll", 0);
			auto const pollFn= [clientSocket, &serverAuth, pollId] {
				SceNetEpollEvent pollEvent{};
				pollEvent.events= SCE_NET_EPOLLIN;
				auto result= sceNetEpollControl(pollId, SCE_NET_EPOLL_CTL_ADD, clientSocket, &pollEvent);
				result= sceNetEpollWait(pollId, &pollEvent, 1, -1);
				if(result > 0) {
					char buffer[888];
					auto const n= sceNetRecv(clientSocket, buffer, sizeof(buffer), 0);
					std::string s(buffer, buffer + n / sizeof(buffer[0]));
					auto const i= s.find('\t');
					tstring accessToken(s.cbegin(), s.cbegin() + i);
					tstring refreshToken(s.cbegin() + i + 1, s.cend());

					// Complete the server authentication by setting the tokens.
					serverAuth.Finish(accessToken.c_str(), refreshToken.c_str());
				}
			};
			auto pollTask= std::async(std::launch::async, pollFn);

			// Await authentication and clean up the polling task.  If the user
			// closed the Web browser without signing into Twitch, the
			// authentication task will return an empty token and the polling
			// wait above will exit with an error and not set the tokens.
			token= authTask.get().c_str();
			sceNetEpollAbort(pollId, 0);
			pollTask.wait();
			sceNetEpollDestroy(pollId);
		} else {
			token= "Cannot connect";
		}
		sceNetSocketClose(clientSocket);
	}
	std::cout << "server auth token:  " << token << std::endl;
}

int main() {
	TestClientAuth();
	TestServerAuth();
	return 0;
}
