#include<fstream>
#include <windows.h>
#include <winuser.h>
#include<thread> // std::thread
#include<chrono> // std::thread
#include "include/lua.hpp"
#include"LuaBridge/LuaBridge.h"
#include "common.h" 
#include "plugin.h"
#include "CWorld.h"
#include "extensions\KeyCheck.h"
#include "extensions\ScriptCommands.h"
#include "eScriptCommands.h"
#include "CMessages.h"

using namespace plugin;
using namespace std;
using namespace luabridge;

bool reload = false;
int abstack(lua_State* L, int number) {
	int n = lua_gettop(L);/* получаем количество элементов в стеке.*/
	++n;
	int no = n + number;
	return no;
};
void writelog(const char x[]) {
	string path = "lualoader\\log.txt";
	fstream f1; {f1.open(path, fstream::in | fstream::out | fstream::app);
	f1 << x << "\n"; }
	f1.close();
};


int wait(lua_State* L) {
	try {
		if (LUA_TNUMBER == lua_type(L, -1)) {// значение число.
			double x = lua_tonumber(L, -1);
			int x2 = (int)x;
			this_thread::sleep_for(chrono::milliseconds(x2));
			return 0;
		}// int
		if (LUA_TSTRING == lua_type(L, -1) || LUA_TBOOLEAN == lua_type(L, -1))
		{
			throw "bad argument in function wait";
		}
		if ( LUA_TBOOLEAN == lua_type(L, -1))
		{
			throw "bad argument in function wait";
		}
		else { this_thread::sleep_for(chrono::milliseconds(1)); }
	}
	catch (const char* x) {	writelog(x);
	}
	return 0;
}
CPed *findplayer(lua_State* L) {
	CPed *player = FindPlayerPed();// получить указатель на игрока.
	return player;// вернуть указатель на игрока.
};

int gethealth(lua_State* L) {
	try {
		if (LUA_TUSERDATA == lua_type(L, -1)) {// указатель на игрока.
			CPed *b = (CPed*)Userdata::get<CPed>(L, abstack(L, -1), false);// получить указатель на игрока. 
			int health = b->m_fHealth; // получить кол-во здоровья игрока.
			lua_pushnumber(L, health);// отправить в стек.	
			return 1;
		}
		else { throw "bad argument in function gethealth option of the player"; }
	}
	catch (const char* x) {
		writelog(x);
		return 0;
	}
	return 0;
};

int sethealth(lua_State* L) {
	try {
		if (LUA_TUSERDATA == lua_type(L, -2)) {// указатель на игрока.
			double x = lua_tonumber(L, -1);// если число.
			int health = (int)x;
			if (x == health && LUA_TNUMBER == lua_type(L, -1)) {
				CPed *b = (CPed*)Userdata::get<CPed>(L, abstack(L, -2), false);// получить указатель на игрока. 
				b->m_fHealth = health;}// уст здоровье игрока.
			else { throw "bad argument in function sethealth option health"; }
		}
		else { throw "bad argument in function sethealth option of the player"; }
	}
	catch (const char* x) {
		writelog(x);
	}
	return 0;
};
int setarmour(lua_State* L) {
	try {
		if (LUA_TUSERDATA == lua_type(L, -2)) {// указатель на игрока.
			double x = lua_tonumber(L, -1);// если число.
			int armour = (int)x;
			if (x == armour && LUA_TNUMBER == lua_type(L, -1)) {
				CPed *b = (CPed*)Userdata::get<CPed>(L, 1, false);// получить указатель на игрока.
				b->m_fArmour = armour;		}// уст броню игрока.
			else { throw "bad argument in function setarmour option health"; }
		}
		else { throw "bad argument in function setarmour option of the player"; }
	}
	catch (const char* x) {
		writelog(x);
	}
	return 0;
};

int givemoney(lua_State* L) {
	try {
		if (LUA_TNUMBER == lua_type(L, -1)) {//money.
			int money = lua_tonumber(L, -1);
				CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;// дать денег  
			}
			else { throw "bad argument in function givemoney"; }
	}
	catch (const char* x) {
		writelog(x);
	}
	return 0;
};

int key(lua_State* L) {
	try {
		if (LUA_TNUMBER == lua_type(L, -1)) {// значение число.
			double key = lua_tonumber(L, -1);
			int x2 = (int)key; 
			//CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 50;// дать денег  
			if (key == x2) {
				if (GetAsyncKeyState(x2) == -32767) {
					lua_pushboolean(L, true);
					return 1;
				}
				else {
					lua_pushboolean(L, false);
					return 1;
				}
			}
			else { throw "bad argument in function key"; }
		}
		else { throw "bad argument in function key"; }
	}
	catch (const char* x) {
		writelog(x);
	}
	return 0;
}

int printmessage(lua_State* L) {
	try {
		if (LUA_TSTRING == lua_type(L, -1)) {//money.
		string msg = lua_tostring(L, -1);
		char str[255];
		strcpy(str, msg.c_str());

			static char x[255];
			snprintf(x, 255,"%s", str);
			CMessages::AddMessageJumpQ(x, 5000, 3);
			return 0;
		}
		else { throw "bad argument in function printmessage"; }
	}
	catch (const char* x) {
		writelog(x);
	}
	return 0;
};
void second(bool &reload) {
	lua_State* L = luaL_newstate();
	luaL_openlibs(L);
	getGlobalNamespace(L)//Пространства имен LuaBridge для регистрации функции и классов, видны только сценариям Lua.
		.beginClass<CPed>("cped")// имя класса в lua.
		.endClass()// закрыть регистрацию класса. 
		.addFunction("findplayer", &findplayer)// возвращает указатель игрока.
        .addCFunction("gethealth", &gethealth)// название функции в lua и c++. уст здоровье.
		.addCFunction("sethealth", &sethealth)// название функции в lua и c++. получить здоровье.
		.addCFunction("setarmour", &setarmour)// название функции в lua и c++. уст броню.
		.addCFunction("givemoney", &givemoney)// название функции в lua и c++. дать денег игроку.
		.addCFunction("keypress", &key)// название функции в lua и c++. уст броню.
		.addCFunction("printmessage", &printmessage)// название функции в lua и c++. уст броню.
		.addCFunction("wait", &wait);// название функции в lua и c++. уст здоровье.
	    luaL_dofile(L, "lualoader\\main.lua"); // Загружает и запускает заданный файл. файл в которым все происходит.	
	while (true)
	{		
		if (KeyPressed(VK_CONTROL)) {// перезагрузка скрипта
           lua_close(L); // закрыть состояние
		   this_thread::sleep_for(chrono::milliseconds(1));
			static unsigned int time = 0;// обнулить таймер.
			if (CTimer::m_snTimeInMilliseconds - time > 500) {
			time = 0;// обнулить таймер
			reload = false;
			}
			break;
		}
	}
	return;
};

class Message {//имя класса
public: Message() {
	Events::gameProcessEvent += [] {//обработчик событий игры
		CPed *player = FindPlayerPed();// найти игрока
		if (!player) return;// проверка найден игрок
		if (reload == false) {
			reload = true;
			thread th(second, std::ref(reload)); th.detach();//	}
		}
	};
}} message;


