#include "CMGameInstance.h"
#include "SocketIOClient.h"

void UCMGameInstance::Login(const FString& Username, const FString& Password)
{
	const auto Request = FHttpModule::Get().CreateRequest();
	Request->SetURL(LobbyAPI + "/login");
	Request->SetVerb("POST");
	Request->SetHeader("Content-Type", "application/json");
	Request->SetHeader("Accept", "application/json");
	Request->SetContentAsString("{\"username\":\"" + Username + "\",\"password\":\"" + Password + "\"}");
	Request->OnProcessRequestComplete().BindUObject(this, &UCMGameInstance::OnRequestToLoginComplete);
	Request->ProcessRequest();
}

void UCMGameInstance::Register(const FString& Username, const FString& Password)
{
	const auto Request = FHttpModule::Get().CreateRequest();
	Request->SetURL(LobbyAPI + "/register");
	Request->SetVerb("POST");
	Request->SetHeader("Content-Type", "application/json");
	Request->SetHeader("Accept", "application/json");
	Request->SetContentAsString("{\"username\":\"" + Username + "\",\"password\":\"" + Password + "\"}");
	Request->OnProcessRequestComplete().BindUObject(this, &UCMGameInstance::OnRequestToRegisterComplete);
	Request->ProcessRequest();
}

void UCMGameInstance::Logout()
{
	const auto Request = FHttpModule::Get().CreateRequest();
	Request->SetURL(LobbyAPI + "/logout");
	Request->SetVerb("POST");
	Request->SetHeader("Authorization", "Bearer " + JwtToken);
	Request->OnProcessRequestComplete().BindUObject(this, &UCMGameInstance::OnRequestToLogoutComplete);
	Request->ProcessRequest();
}

void UCMGameInstance::CreateLobby()
{
	const auto Request = FHttpModule::Get().CreateRequest();
	Request->SetURL(LobbyAPI + "/create");
	Request->SetVerb("GET");
	Request->SetHeader("Authorization", "Bearer " + JwtToken);
	Request->SetHeader("Accept", "application/json");
	Request->OnProcessRequestComplete().BindUObject(this, &UCMGameInstance::OnRequestToCreateLobbyComplete);
	Request->ProcessRequest();
}

void UCMGameInstance::JoinLobby(const int Port)
{
	if (APlayerController* PC = GetWorld()->GetFirstPlayerController())
	{
		PC->ConsoleCommand("open " + ServerFQDN + ":" + FString::FromInt(Port));
	}
}

void UCMGameInstance::Init()
{
	Super::Init();

	Socket = ISocketIOClientModule::Get().NewValidNativePointer();

	Socket->Connect("wss://cm.api.philipwhite.dev/");
	Socket->OnConnectedCallback = [this](const FString& SocketID, const FString& SessionID)
	{
		UE_LOG(LogTemp, Log, TEXT("Connected: %s %s"), *SocketID, *SessionID);
		if (IsDedicatedServerInstance())
		{
			FParse::Value(FCommandLine::Get(), TEXT("lobbyID="), LobbyID);
			FString CMServerSecret;
			FParse::Value(FCommandLine::Get(), TEXT("CMServerSecret="), CMServerSecret);
			const TSharedPtr<FJsonObject> AuthorityData = MakeShareable(new FJsonObject);
			AuthorityData->SetStringField("lobbyID", LobbyID);
			AuthorityData->SetStringField("secret", CMServerSecret);
			Socket->Emit(TEXT("authority"), AuthorityData);
		}
	};

	Socket->OnEvent(LobbyID + "/A", [this](const FString& Event, const TSharedPtr<FJsonValue>& Message)
	{
		UE_LOG(LogTemp, Log, TEXT("Received: %s"), *USIOJConvert::ToJsonString(Message));
	});

	Socket->Emit(TEXT("MyEmit"), TEXT("hi"));
}

void UCMGameInstance::Shutdown()
{
	Super::Shutdown();
	if (Socket.IsValid())
	{
		ISocketIOClientModule::Get().ReleaseNativePointer(Socket);
		Socket = nullptr;
	}
}

void UCMGameInstance::OnRequestToLoginComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (bWasSuccessful)
	{
		const auto JsonReader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
		if (TSharedPtr<FJsonObject> JsonObject; FJsonSerializer::Deserialize(JsonReader, JsonObject))
		{
			const auto JsonToken = JsonObject->GetStringField("token");
			const auto JsonUsername = JsonObject->GetStringField("user");
			JwtToken = JsonToken;
			AccountUsername = JsonUsername;
			OnLoginComplete.Broadcast(true);
		}
		else
		{
			OnLoginComplete.Broadcast(false);
		}
	}
	else
	{
		OnLoginComplete.Broadcast(false);
	}
}

void UCMGameInstance::OnRequestToRegisterComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) const
{
	if (Response->GetResponseCode() == 201)
	{
		OnRegisterComplete.Broadcast(true);
	}
	else
	{
		OnRegisterComplete.Broadcast(false);
	}
}

void UCMGameInstance::OnRequestToLogoutComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (bWasSuccessful)
	{
		AccountUsername = "";
		JwtToken = "";
		OnLogoutComplete.Broadcast(true);
	}
	else
	{
		OnLogoutComplete.Broadcast(false);
	}
}

void UCMGameInstance::OnRequestToCreateLobbyComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (bWasSuccessful)
	{
		const auto JsonReader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
		if (TSharedPtr<FJsonObject> JsonObject; FJsonSerializer::Deserialize(JsonReader, JsonObject))
		{
			const auto JsonLobbyID = JsonObject->GetStringField("lobbyID");
			const auto JsonPort = JsonObject->GetIntegerField("port");
			LobbyID = JsonLobbyID;
			ServerPort = JsonPort;
			OnJoinLobbyComplete.Broadcast(true);
			JoinLobby(ServerPort);
		}
		else
		{
			OnJoinLobbyComplete.Broadcast(false);
		}
	}
	else
	{
		OnJoinLobbyComplete.Broadcast(false);
	}
}
