#include "pch.h"
#include "Internal.h"
#include "DdeServer.h"

using namespace TwitchInGames;

ClientAuth::ClientAuth() {}

ClientAuth::~ClientAuth() {
	Cancel();
}

std::future<tstring> ClientAuth::StartAuth(string_t clientId, string_t redirectUri, std::vector<string_t> const& scopes) {
	// Create the DDE server.
	if(ddeServer) {
		throw TwitchException(FromPlatformError(ERROR_INVALID_OPERATION));
	}
	ddeServer= std::make_shared<DdeServer>(redirectUri);

	// Start the authentication.
	tstring state;
	auto result= BrowserAuth::Launch(clientId, redirectUri, _T("token"), scopes, state);
	auto fn= [this, state](std::future<tstring>&& result) {
		// Wait for the DDE server to provide the URL.
		auto uri= ddeServer->GetUri();

		// Validate the response, check the state, and extract the token.
		tstring token;
		auto i= uri.find(L'#');
		if(i != uri.npos) {
			uri.erase(0, i + 1);
			auto returnedState= ExtractToken(uri, _T("state"));
			if(returnedState == state) {
				token= ExtractToken(uri, _T("access_token"));
			}
		}

		// Set this session's token, destroy the DDE server, and return the
		// browser authentication result (i.e., the token).
		Stop(token.c_str());
		ddeServer.reset();
		return result.get();
	};
	return std::async(std::launch::deferred, fn, std::move(result));
}

void ClientAuth::Cancel() {
	// Tell the DDE server to cancel.  This will cause its GetUri method to
	// return an empty result in the lambda in the StartAuth method above,
	// resulting in an empty token.
	auto local= ddeServer; // Create a thread-safe copy.
	if(local) {
		local->Cancel();
	}
}
