#include "pch.h"
#include "http/HttpRequest.h"
#include "twitchsdk/core/json/reader.h"
#include "Internal.h"

using namespace ttv;
using namespace TwitchInGames;

namespace {
	tstring const helixUrl = _T("https://api.twitch.tv/helix/");
}

std::future<tstring> Clip::Create(tstring const& clientId, tstring const& token, tstring const& broadcasterId) {
	// Validate the arguments.
	if(clientId.empty()) {
		DebugWriteLine(_T("[Clip::Create] Invalid client identifier"));
		throw TwitchException(FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
	if(token.empty()) {
		DebugWriteLine(_T("[Clip::Create] Invalid token"));
		throw TwitchException(FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
	if(broadcasterId.empty()) {
		DebugWriteLine(_T("[Clip::Create] Invalid broadcaster identifier"));
		throw TwitchException(FromPlatformError(ERROR_BAD_ARGUMENTS));
	}

	auto fn= [clientId, token, broadcasterId] {
		// Create the requested clip.
		auto url= helixUrl + _T("clips?broadcaster_id=") + broadcasterId;
		auto httpResponse= HttpRequest(clientId, token).Post(url);
		ThrowIfResponseFailed(httpResponse);

		// Parse the response as JSON.
		json::Value jsonVal;
		json::Reader jsonReader;
		auto const& response= httpResponse.Response;
		bool parseSucceeded= jsonReader.parse(response.data(), response.data() + response.size(), jsonVal);
		if(!parseSucceeded) {
			DebugWriteLine(_T("[Clip::Create] JSON parsing failed"));
			throw TwitchException(FromPlatformError(ERROR_INVALID_RESPONSE));
		}

		// Send a science event.
		SendTokenScienceEvent(clientId, token, _T("sdk_clip_create"), { { _T("broadcaster_id"), broadcasterId } });

		// Return the identifier of the created clip.
		auto const& jsonClip= jsonVal["data"][static_cast<size_t>(0)];
		auto const& jsonId= jsonClip["id"];
		return ToTstring(jsonId.asString());
	};
	return std::async(std::launch::deferred, fn);
}

std::future<Clip> Clip::Fetch(tstring const& clientId, tstring const& id) {
	// Validate the arguments.
	if(clientId.empty()) {
		DebugWriteLine(_T("[Clip::Fetch] Invalid client identifier"));
		throw TwitchException(FromPlatformError(ERROR_BAD_ARGUMENTS));
	}
	if(id.empty()) {
		DebugWriteLine(_T("[Clip::Fetch] Invalid clip identifier"));
		throw TwitchException(FromPlatformError(ERROR_BAD_ARGUMENTS));
	}

	auto fn= [clientId, id] {
		// Fetch the requested clip.
		auto url= helixUrl + _T("clips?id=") + id;
		auto httpResponse= HttpRequest(clientId).Get(url);
		ThrowIfResponseFailed(httpResponse);

		// Parse the response as JSON.
		json::Value jsonVal;
		json::Reader jsonReader;
		auto const& response= httpResponse.Response;
		bool parseSucceeded= jsonReader.parse(response.data(), response.data() + response.size(), jsonVal);
		if(!parseSucceeded) {
			DebugWriteLine(_T("[Clip::Fetch] JSON parsing failed"));
			throw TwitchException(FromPlatformError(ERROR_INVALID_RESPONSE));
		}

		// Send a science event.
		SendUserScienceEvent(clientId, tstring(), _T("sdk_clip_get"), { { _T("clip_id"), id } });

		// Get references for all of the clip fields.
		auto const& jsonClip= jsonVal["data"][static_cast<size_t>(0)];
		auto const& jsonId= jsonClip["id"];
		auto const& jsonUrl= jsonClip["url"];
		auto const& jsonEmbedUrl= jsonClip["embed_url"];
		auto const& jsonBroadcasterId= jsonClip["broadcaster_id"];
		auto const& jsonCreatorId= jsonClip["creator_id"];
		auto const& jsonVideoId= jsonClip["video_id"];
		auto const& jsonGameId= jsonClip["game_id"];
		auto const& jsonLanguage= jsonClip["language"];
		auto const& jsonTitle= jsonClip["title"];
		auto const& jsonViewCount= jsonClip["view_count"];
		auto const& jsonCreatedAt= jsonClip["created_at"];
		auto const& jsonThumbnailUrl= jsonClip["thumbnail_url"];

		// Populate and return a Clip instance.
		Clip clip;
		clip.id= ToTstring(jsonId.asString());
		clip.url= ToTstring(jsonUrl.asString());
		clip.embedUrl= ToTstring(jsonEmbedUrl.asString());
		clip.broadcasterId= ToTstring(jsonBroadcasterId.asString());
		clip.creatorId= ToTstring(jsonCreatorId.asString());
		clip.videoId= ToTstring(jsonVideoId.asString());
		clip.gameId= ToTstring(jsonGameId.asString());
		clip.language= ToTstring(jsonLanguage.asString());
		clip.title= ToTstring(jsonTitle.asString());
		clip.viewCount= static_cast<unsigned>(jsonViewCount.asUInt());
		clip.createdAt= ToTstring(jsonCreatedAt.asString());
		clip.thumbnailUrl= ToTstring(jsonThumbnailUrl.asString());
		return clip;
	};
	return std::async(std::launch::deferred, fn);
}
