--[[
local warn = function(...)
	warn(...)
end
]]
local cPcall = function(func, ...)
	local ran, err = pcall(coroutine.resume, coroutine.create(func), ...)

	if err then
		warn(':: ADONIS_ERROR ::',err)
		logError(tostring(err))
	end

	return ran, err
end

local Pcall = function(func, ...)
	local ran, err = pcall(func, ...)

	if err then
		logError(tostring(err))
	end

	return ran, err
end

local Routine = function(func, ...)
	return coroutine.resume(coroutine.create(func), ...)
end

local Immutable = function(...)
	local mut = coroutine.wrap(function(...)
		while true do
			coroutine.yield(...)
		end
	end)
	mut(...)
	return mut
end

local player = game:GetService("Players").LocalPlayer
local Fire, Detected = nil,nil
local wrap = coroutine.wrap
local Kill; Kill = Immutable(function(info)
	--if true then print(info or "SOMETHING TRIED TO CRASH CLIENT?") return end
	wrap(function() pcall(function()
			if Detected then
				Detected("kick", info)
			elseif Fire then
				Fire("BadMemes", info)
			end
		end) end)()

	wrap(function() pcall(function()
			wait(1)
			service.Player:Kick(info)
		end) end)()

	wrap(function() pcall(function()
			wait(5)
			while true do
				pcall(spawn,function()
					spawn(Kill())
					-- memes
				end)
			end
		end) end)()
end);

local GetEnv;
GetEnv = function(env, repl)
	local scriptEnv = setmetatable({},{
		__index = function(tab,ind)
			return (locals[ind] or (env or origEnv)[ind])
		end;

		__metatable = unique;
	})

	if repl and type(repl)=="table" then
		for ind, val in pairs(repl) do
			scriptEnv[ind] = val
		end
	end

	return scriptEnv
end

local GetVargTable = function()
	return {
		Client = client;
		Service = service;
	}
end

local LoadModule = function(plugin, yield, envVars, noEnv)
	local plugran, plug = pcall(require, plugin)

	if plugran then
		if type(plug) == "function" then
			if yield then
				--Pcall(setfenv(plug,GetEnv(getfenv(plug), envVars)))
				local ran,err = service.TrackTask("Plugin: ".. tostring(plugin), (noEnv and plug) or setfenv(plug, GetEnv(getfenv(plug), envVars)), GetVargTable(), GetEnv)

				if not ran then
					warn("Module encountered an error while loading: "..tostring(plugin))
					warn(tostring(err))
				end
			else
				--service.Threads.RunTask("PLUGIN: "..tostring(plugin),setfenv(plug,GetEnv(getfenv(plug), envVars)))
				local ran,err = service.TrackTask("Thread: Plugin: ".. tostring(plugin), (noEnv and plug) or setfenv(plug, GetEnv(getfenv(plug), envVars)), GetVargTable(), GetEnv)

				if not ran then
					warn("Module encountered an error while loading: "..tostring(plugin))
					warn(tostring(err))
				end
			end
		else
			client[plugin.Name] = plug
		end
	else
		warn("Error while loading client module", plugin, plug)
	end
end;

log("Client setmetatable");

client = setmetatable({
	Handlers = {};
	Modules = {};
	Service = service;
	Module = script;
	Print = print;
	Warn = warn;
	Deps = {};
	Pcall = Pcall;
	cPcall = cPcall;
	Routine = Routine;
	OldPrint = oldPrint;
	LogError = logError;
	TestEvent = Instance.new("RemoteEvent");

	Disconnect = function(info)
		service.Player:Kick(info or "Disconnected from server")
		--wait(30)
		--client.Kill()(info)
	end;

	--Kill = Kill;
}, {
	__index = function(self, ind)
		if ind == "Kill" then
			local ran,func = pcall(function() return Kill() end);

			if not ran or type(func) ~= "function" then
				service.Players.LocalPlayer:Kick("Adonis (PlrClientIndexKlErr)");
				while true do end
			end

			return func;
		end
	end
});

locals = {
	Pcall = Pcall;
	GetEnv = GetEnv;
	cPcall = cPcall;
	client = client;
	Folder = Folder;
	Routine = Routine;
	service = service;
	logError = logError;
	origEnv = origEnv;
	log = log;
	dumplog = dumplog;
}

log("Create service metatable");

service = require(Folder.Shared.Service)(function(eType, msg, desc, ...)
	--warn(eType, msg, desc, ...)
	local extra = {...}
	if eType == "MethodError" then
		--Kill()("Shananigans denied")
		--player:Kick("Method error")
		--service.Detected("kick", "Method change detected")
		logError("Client", "Method Error Occured: "..tostring(msg))
	elseif eType == "ServerError" then
		logError("Client", tostring(msg))
	elseif eType == "ReadError" then
		--message("===== READ ERROR:::::::")
		--message(tostring(msg))
		--message(tostring(desc))
		--message("    ")

		Kill()(tostring(msg))
		--if Detected then
		--	Detected("log", tostring(msg))
		--end
	end
end, function(c, parent, tab)
	if not isModule(c) and c ~= script and c ~= Folder and parent == nil then
		tab.UnHook()
	end
end, ServiceSpecific, GetEnv(nil, {client = client}))