//====================================================================================================
//
// Name: UNLOZE Forum Integration.
// Author: .George & zaCade (Original by Botox)
// Description: Handles forum access ingame.
//
//====================================================================================================
#include <sourcemod>
#include <SteamWorks>
#include <unloze>
#include <UNLOZE.secret> //#define UNLOZE_APIKEY here

#pragma newdecls required

/* STRINGS */
char G_sGroup[MAXPLAYERS+1][64];

/* BOOLS */
bool G_bPreAdminChecked[MAXPLAYERS+1];
bool G_bResponseFailed[MAXPLAYERS+1];
bool G_bResponsePassed[MAXPLAYERS+1];

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name         = "UNLOZE Forum Integration",
	author       = ".George & zaCade (Original by Botox)",
	description  = "Handles forum access ingame",
	version      = "1.2.1"
};

//----------------------------------------------------------------------------------------------------
// Purpose: Late load
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	/* Late load */
	for(int client = 1; client <= MaxClients; client++)
	{
		if(IsClientConnected(client))
			OnClientConnected(client);

		if(IsClientAuthorized(client) && !IsFakeClient(client))
		{
			char sSteamID32[32];
			if(GetClientAuthId(client, AuthId_Steam2, sSteamID32, sizeof(sSteamID32)))
				OnClientAuthorized(client, sSteamID32);
		}
	}
}


//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
	CreateNative("AsyncHasSteamIDReservedSlot", Native_AsyncHasSteamIDReservedSlot);

	RegPluginLibrary("UNLOZE_ForumIntegration");

	return APLRes_Success;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnRebuildAdminCache(AdminCachePart part)
{
	if (part != AdminCache_Admins)
		return;

	CreateTimer(1.0, OnRebuildAdminCachePost, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnRebuildAdminCachePost(Handle hTimer)
{
	for (int client = 1; client <= MaxClients; client++)
	{
		if(G_bResponsePassed[client] && G_bPreAdminChecked[client])
			ApplyGroupFlags(client);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientConnected(int client)
{
	G_bPreAdminChecked[client] = false;
	G_bResponseFailed[client] = false;
	G_bResponsePassed[client] = false;

	G_sGroup[client][0] = 0;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientDisconnect(int client)
{
	G_bPreAdminChecked[client] = false;
	G_bResponseFailed[client] = false;
	G_bResponsePassed[client] = false;

	G_sGroup[client][0] = 0;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientAuthorized(int client, const char[] sSteamID32)
{
	if (IsFakeClient(client))
		return;

	char sSteamID64[32];
	SteamID32toSteamID64(sSteamID32, sSteamID64, sizeof(sSteamID64));

	int iSerial = GetClientSerial(client);

	char sRequest[256];
	FormatEx(sRequest, sizeof(sRequest), "https://unloze.com/api/private_api.php?api_key=%s&steam_id=%s", UNLOZE_APIKEY, sSteamID64);

	Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest);
	if (!hRequest ||
		!SteamWorks_SetHTTPCallbacks(hRequest, OnClientAuthorized_OnTransferComplete) ||
		!SteamWorks_SetHTTPRequestContextValue(hRequest, iSerial) ||
		!SteamWorks_SendHTTPRequest(hRequest))
	{
		delete hRequest;
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int OnClientAuthorized_OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, int iSerial)
{
	int client = GetClientFromSerial(iSerial);

	if (!client) //Player disconnected.
	{
		delete hRequest;
		return;
	}

	if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
	{
		G_bResponseFailed[client] = true;

		if (G_bPreAdminChecked[client])
			NotifyPostAdminCheck(client);

		delete hRequest;
		return;
	}

	SteamWorks_GetHTTPResponseBodyCallback(hRequest, OnClientAuthorized_OnTransferResponse, iSerial);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int OnClientAuthorized_OnTransferResponse(char[] sData, int iSerial)
{
	int client = GetClientFromSerial(iSerial);

	if (!client) //Player disconnected.
		return;

	TrimString(sData);
	StripQuotes(sData);

	strcopy(G_sGroup[client], sizeof(G_sGroup[]), sData);

	G_bResponsePassed[client] = true;

	if (G_bPreAdminChecked[client])
		NotifyPostAdminCheck(client);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnClientPreAdminCheck(int client)
{
	G_bPreAdminChecked[client] = true;

	if (G_bResponsePassed[client] || G_bResponseFailed[client])
		return Plugin_Continue;

	RunAdminCacheChecks(client);
	return Plugin_Handled;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPostAdminFilter(int client)
{
	ApplyGroupFlags(client);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock void ApplyGroupFlags(int client)
{
	if (!G_bResponsePassed[client])
		return;

	AdminId AdmID;
	GroupId GrpID;

	if ((AdmID = GetUserAdmin(client)) == INVALID_ADMIN_ID)
	{
		LogMessage("Creating new admin for %L", client);

		AdmID = CreateAdmin();
		SetUserAdmin(client, AdmID, true);
	}

	if ((GrpID = FindAdmGroup(G_sGroup[client])) != INVALID_GROUP_ID)
	{
		if (AdminInheritGroup(AdmID, GrpID))
		{
			LogMessage("%L added to group %s", client, G_sGroup[client]);
		}
	}
	else
	{
		LogMessage("%L group not found %s", client, G_sGroup[client]);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_AsyncHasSteamIDReservedSlot(Handle plugin, int numParams)
{
	char sSteamID32[32];
	GetNativeString(1, sSteamID32, sizeof(sSteamID32));

	AsyncHasSteamIDReservedSlotCallbackFunc callback;
	callback = GetNativeCell(2);

	any data;
	data = GetNativeCell(3);

	char sSteamID64[32];
	SteamID32toSteamID64(sSteamID32, sSteamID64, sizeof(sSteamID64));

	char sRequest[256];
	FormatEx(sRequest, sizeof(sRequest), "https://unloze.com/api/private_api.php?api_key=%s&steam_id=%s", UNLOZE_APIKEY, sSteamID64);

	DataPack hDataPack = new DataPack();
	hDataPack.WriteString(sSteamID32);
	hDataPack.WriteFunction(callback);
	hDataPack.WriteCell(plugin);
	hDataPack.WriteCell(data);

	Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest);
	if (!hRequest ||
		!SteamWorks_SetHTTPCallbacks(hRequest, Native_AsyncHasSteamIDReservedSlot_OnTransferComplete) ||
		!SteamWorks_SetHTTPRequestContextValue(hRequest, hDataPack) ||
		!SteamWorks_SendHTTPRequest(hRequest))
	{
		delete hRequest;
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_AsyncHasSteamIDReservedSlot_OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, DataPack hDataPack)
{
	if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
	{
		char sData[32] = "NOGROUP";
		Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(sData, hDataPack);

		delete hRequest;
		return;
	}

	SteamWorks_GetHTTPResponseBodyCallback(hRequest, Native_AsyncHasSteamIDReservedSlot_OnTransferResponse, hDataPack);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(char[] sData, DataPack hDataPack)
{
	hDataPack.Reset();

	char sSteamID32[32];
	hDataPack.ReadString(sSteamID32, sizeof(sSteamID32));

	AsyncHasSteamIDReservedSlotCallbackFunc callback;
	callback = view_as<AsyncHasSteamIDReservedSlotCallbackFunc>(hDataPack.ReadFunction());

	Handle plugin;
	plugin = hDataPack.ReadCell();

	any data;
	data = hDataPack.ReadCell();

	TrimString(sData);
	StripQuotes(sData);

	int result;
	if (StrEqual(sData, "Game-Donator", false))
		result = 1;
	else
		result = 0;

	Call_StartFunction(plugin, callback);
	Call_PushString(sSteamID32);
	Call_PushCell(result);
	Call_PushCell(data);
	Call_Finish();

	delete hDataPack;
	return;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock bool SteamID32toSteamID64(const char[] sSteamID32, char[] sSteamID64, int iSize)
{
	if (strlen(sSteamID32) < 11 || strncmp(sSteamID32[0], "STEAM_", 6))
	{
		sSteamID64[0] = 0;
		return false;
	}

	int iUpper = 765611979;
	int isSteam64ID = StringToInt(sSteamID32[10]) * 2 + 60265728 + sSteamID32[8] - 48;

	int iDiv = isSteam64ID / 100000000;
	int iIdx = 9 - (iDiv ? (iDiv / 10 + 1) : 0);

	iUpper += iDiv;

	IntToString(isSteam64ID, sSteamID64[iIdx], iSize - iIdx);
	iIdx = sSteamID64[9];

	IntToString(iUpper, sSteamID64, iSize);
	sSteamID64[9] = iIdx;

	return true;
}