#pragma semicolon 1

#define DEBUG

#define PLUGIN_AUTHOR "jenz"
#define PLUGIN_VERSION "1.00"
#define generic_length 256

#include <sourcemod>
#include <sdktools>

#pragma newdecls required

int present = 0;
int targethuman = 0;
int stuckcounterX = 0;
int stuckcounterY = 0;
bool hunt_or_mimic = false;
Database database_connection_input;

public Plugin myinfo = 
{
	name = "coordinates for the bot",
	author = PLUGIN_AUTHOR,
	description = "hello ",
	version = PLUGIN_VERSION,
	url = ""
};

public void OnClientDisconnect(int client)
{
	if (present == client)
	{
		present = 0;
		mysql_enable_disable_connected(0);
	}
}

public void OnPluginStart()
{
	//talking
	RegConsoleCmd("sm_autism", cmd_talk, "talking to the bot through java application");
	
	//hooks
	HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy);
	HookEvent("player_team", event_playerteam, EventHookMode_PostNoCopy);
	
	//global DB
	char error_connect[generic_length];
	if (SQL_CheckConfig("css_autism_bot_info"))
		database_connection_input = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection_input == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	
	//mysql
	sql_create_table();
}

public Action cmd_talk(int client, int args)
{	
	char info[generic_length];
	GetCmdArgString(info, sizeof(info));
	if (strlen(info) == 0)
	{
		PrintToChat(client, "Add a message to the command if autism bot is ingame");
		return Plugin_Handled;
	}
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info")) 
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	//256 not enough
	char query_start[generic_length];
	Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`chatting` (`chatmessage`, `responsemessage`) VALUES ('%s', '')", info);
	//PrintToChatAll("query_start: %s", query_start);
	mysql_exec_prepared_statement(database_connection, query_start);
	delete database_connection;
	return Plugin_Handled;
}

public void OnPluginEnd()
{
	delete database_connection_input;
}

public Action event_playerteam(Event event, const char[] name, bool dontBroadcast)
{
	int client = GetClientOfUserId(event.GetInt("userid"));
	if (client == present)
	{
		//PrintToChatAll("called event_playerteam");
		int team = event.GetInt("team");
		//PrintToChatAll("team: %i", team);
		if (team == 2 || team == 3)
			mysql_bot_not_spec();
	}
}

public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast)
{
	targethuman = 0;
	int server_port = GetConVarInt(FindConVar("hostport"));
	if (server_port == 27015)
	{
		mysql_update_playercount();
	}
	hunt_or_mimic = false;
	if (present)
		mysql_clean_movement_input();
}

public void OnMapStart()
{
	sql_create_table();
	CreateTimer(1.3, recursive_pressing, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}

public bool TraceEntityFilterPlayer(int entity, int contentsMask)
{
	return (entity > GetMaxClients() || !entity);
}

public Action recursive_pressing(Handle timer, any data)
{
	if (present && IsPlayerAlive(present))
	{
		float present_bot_coords[3];
		GetClientAbsOrigin(present, present_bot_coords);
		if (!IsValidClient(targethuman) || GetClientTeam(targethuman) != 3 || !IsPlayerAlive(targethuman))
		{
			hunt_or_mimic = false;
			float lowest_distance = 1000000.0;
			for (int i = 1; i <= MaxClients; i++)
				if (IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == 3 && i != present)
				{
					float pos[3];
					GetClientAbsOrigin(i, pos);
					float dx = present_bot_coords[0] - pos[0];
					float dy = present_bot_coords[1] - pos[1];
					float dz = FloatAbs(present_bot_coords[2] - pos[2]);
					float dist = SquareRoot(dx*dx + dy*dy + dz*dz);
					if (dist < lowest_distance)
					{
						lowest_distance = dist;
						targethuman = i;
					}
				}
		}
		//get bot in distance, mimic all input until CT dead/round over
		
		
		//copy all input to track each origin correctly on path
		//prioritize with global lowest distance what coord point is closest to bot to start mimic entry
		//from which it can mimic input of player forward on each round, boolean
		
		if (IsValidClient(targethuman))
		{
			float target_human_coords[3];
			int distance_limit = 105;
			GetClientAbsOrigin(targethuman, target_human_coords);
			float xyz[3];
			float dx = present_bot_coords[0] - target_human_coords[0];
			float dy = present_bot_coords[1] - target_human_coords[1];
			float dz = FloatAbs(present_bot_coords[2] - target_human_coords[2]);
			float dist = SquareRoot(dx*dx + dy*dy + dz*dz);
			//PrintToChatAll("dist: %f", dist);
			if (dist < distance_limit)
				hunt_or_mimic = true;
			dx = present_bot_coords[0] - target_human_coords[0];
			dy = present_bot_coords[1] - target_human_coords[1];
			dz = FloatAbs(present_bot_coords[2] - target_human_coords[2]);
			xyz[0] = dx;
			xyz[1] = dy;
			xyz[2] = dz;
			int keys = GetClientButtons(targethuman);
			char keyinput[generic_length];
			//if true mimicing human input
			if (hunt_or_mimic)
			{
				if (keys & IN_FORWARD)
				{
					StrCat(keyinput, sizeof(keyinput), "-back; wait 5; +forward; wait 5;");
				}
				else if (keys & IN_BACK)
				{
					StrCat(keyinput, sizeof(keyinput), "-forward; wait 5; +back; wait 5;");
				}
				if (keys & IN_MOVELEFT)
				{
					StrCat(keyinput, sizeof(keyinput), "-moveright; wait 5; +moveleft; wait 5;");
				}
				else if (keys & IN_MOVERIGHT)
				{
					StrCat(keyinput, sizeof(keyinput), "-moveleft; wait 5; +moveright; wait 5;");
				}
			}
			if (keys & IN_JUMP)
			{
				StrCat(keyinput, sizeof(keyinput), "+jump; ");
			}
			if (keys & IN_DUCK)
			{
				StrCat(keyinput, sizeof(keyinput), "+duck; ");
			}
			//PrintToChatAll("targethuman: %N", targethuman);
			float clientangles[3];
			GetClientAbsAngles(targethuman, clientangles);
			mysql_send_input(keyinput, clientangles, xyz, target_human_coords, hunt_or_mimic);
		}
	}
	return Plugin_Handled;
}

stock bool IsValidClient(int client)
{
	if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
	{
		return true;
	}
	return false;
}

public void OnClientPostAdminCheck(int client)
{
	//STEAM_0:1:34783317
	//STEAM_0:1:60189040
	//[U:1:120378081]
	//[U:1:69566635]
	char auth[50];
	GetClientAuthId(client, AuthId_Engine, auth, sizeof(auth)); 
	if (StrEqual("[U:1:120378081]", auth, false))
	{
		mysql_enable_disable_connected(1);
		present = client;
	}
	else if (StrEqual("STEAM_0:1:60189040", auth, false))
	{
		mysql_enable_disable_connected(1);
		present = client;
	}
}

public void sql_create_table()
{
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info")) 
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	//256 not enough
	char query_start[generic_length * 3];
	Format(query_start, sizeof(query_start), "CREATE TABLE IF NOT EXISTS unloze_css_autism_bot.`bot status` (`connected` BOOL DEFAULT false, `spectate` BOOL DEFAULT true, `ID` INT NOT NULL DEFAULT 1, `playercount` INT DEFAULT 0, PRIMARY KEY (`ID`))");
	mysql_exec_prepared_statement(database_connection, query_start);
	Format(query_start, sizeof(query_start), "CREATE TABLE IF NOT EXISTS unloze_css_autism_bot.`bot movement input` (`keyinput` text NOT NULL, `clientangles_0` DECIMAL(13, 8) DEFAULT 0.000, `clientangles_1` DECIMAL(13, 8) DEFAULT 0.000, `clientangles_2` DECIMAL(13, 8) DEFAULT 0.000, `xyz_0` DECIMAL(13, 8) DEFAULT 0.000, `xyz_1` DECIMAL(13, 8) DEFAULT 0.000, `xyz_2` DECIMAL(13, 8) DEFAULT 0.000, `client_coord_0` DECIMAL(13, 8) DEFAULT 0.000, `client_coord_1` DECIMAL(13, 8) DEFAULT 0.000, `client_coord_2` DECIMAL(13, 8) DEFAULT 0.000, `hunt_or_mimic` BOOLEAN DEFAULT false, `stuckX` BOOLEAN DEFAULT false, `stuckY` BOOLEAN DEFAULT false, `entry_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP)");
	mysql_exec_prepared_statement(database_connection, query_start);
	Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot status` (connected, spectate, ID) VALUES (0, 1, 1) ON DUPLICATE KEY UPDATE connected = VALUES(connected), spectate = VALUES(spectate)");
	mysql_exec_prepared_statement(database_connection, query_start);
	Format(query_start, sizeof(query_start), "CREATE TABLE IF NOT EXISTS unloze_css_autism_bot.`chatting` (`chatmessage` text NOT NULL, `responsemessage` text NOT NULL)");
	mysql_exec_prepared_statement(database_connection, query_start);
	delete database_connection;
}

public void mysql_clean_movement_input()
{
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info")) 
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	char query_start[generic_length];
	Format(query_start, sizeof(query_start), "delete from unloze_css_autism_bot.`bot movement input`");
	mysql_exec_prepared_statement(database_connection, query_start);
}

public void mysql_update_playercount()
{
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info")) 
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	char query_start[generic_length];
	Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot status` (playercount, ID) VALUES (%i, 1) ON DUPLICATE KEY UPDATE playercount = %i", MaxClients, MaxClients);
	mysql_exec_prepared_statement(database_connection, query_start);
	delete database_connection;
}

public void mysql_bot_not_spec()
{
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info")) 
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	char query_start[generic_length];
	Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot status` (connected, spectate, ID) VALUES (1, 0, 1) ON DUPLICATE KEY UPDATE connected = VALUES(connected), spectate = VALUES(spectate)");
	mysql_exec_prepared_statement(database_connection, query_start);
}

public void mysql_enable_disable_connected(int state)
{
	char error_connect[generic_length];
	Database database_connection;
	if (SQL_CheckConfig("css_autism_bot_info"))
		database_connection = SQL_Connect("css_autism_bot_info", true, error_connect, sizeof(error_connect));
	if (database_connection == null)
		PrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to maria-DB!");
	char query_start[generic_length];
	if (!state)
		Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot status` (connected, spectate, ID) VALUES (0, 1, 1) ON DUPLICATE KEY UPDATE connected = VALUES(connected), spectate = VALUES(spectate)");
	else
		Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot status` (connected, spectate, ID) VALUES (1, 1, 1) ON DUPLICATE KEY UPDATE connected = VALUES(connected), spectate = VALUES(spectate)");
	//PrintToChatAll("query_start: %s", query_start);
	mysql_exec_prepared_statement(database_connection, query_start);
	delete database_connection;
}

public void mysql_send_input(char []keyinput, float clientangles[3], float xyz[3], float client_coord[3], bool hunt_or_mimicb)
{
	//TODO maybe add autism bot coords too as information
	char query_start[generic_length];
	float flVel[3];
	GetEntPropVector(present, Prop_Data, "m_vecAbsVelocity", flVel);
	int stuckX = 0;
	int stuckY = 0;
	int stuckcap = 6;
	float mincapvelocity = 10.0;
	if (flVel[0] < mincapvelocity)
	{
		stuckcounterX++;
		if (stuckcounterX > stuckcap)
		{
			stuckcounterX = 0;
			stuckX = 1;
		}
	}
	if (flVel[1] < mincapvelocity)
	{
		stuckcounterY++;
		if (stuckcounterY > stuckcap)
		{
			stuckcounterY = 0;
			stuckY = 1;
		}
	}
	Format(query_start, sizeof(query_start), "INSERT INTO unloze_css_autism_bot.`bot movement input` VALUES ('%s', %f, %f, %f, %f, %f, %f, %f, %f, %f, %i, %i, %i, NOW())", keyinput, clientangles[0], clientangles[1], clientangles[2], xyz[0], xyz[1], xyz[2], client_coord[0], client_coord[1], client_coord[2], hunt_or_mimicb, stuckX, stuckY);
	mysql_exec_prepared_statement(database_connection_input, query_start);
	
	//PrintToChatAll("flVel: %f %f %f", flVel[0], flVel[1], flVel[2]);
	//PrintToChatAll("query_start: %s", query_start);
}

public void mysql_exec_prepared_statement(Database database_connection, char []query_statement)
{
	char error[generic_length];
	DBStatement create_statement = SQL_PrepareQuery(database_connection, query_statement, error, sizeof(error));
	if (create_statement == INVALID_HANDLE)
	{
		CloseHandle(create_statement);
		return;
	}
	SQL_Execute(create_statement);
	CloseHandle(create_statement);
}