if SERVER then
	util.AddNetworkString("ulx_steamid")
end

if CLIENT then
	net.Receive("ulx_steamid", function()
		local targ_ply = net.ReadEntity()
		if !IsValid(targ_ply) then return end
		SetClipboardText(targ_ply:SteamID())
		chat.AddText(Color(151, 211, 255), "SteamID: \"", Color(0, 255, 0), targ_ply:SteamID(), Color(151, 211, 255), "\" successfully copied!")
	end)
end

function ulx.id(calling_ply, target_ply)
	net.Start("ulx_steamid")
		net.WriteEntity(target_ply)
	net.Send(calling_ply)
end
local id = ulx.command("Information", "ulx id", ulx.id, "!id", true)
id:addParam{type=ULib.cmds.PlayerArg}
id:defaultAccess(ULib.ACCESS_ADMIN)
id:help("Copies steamid of target.")

if SERVER then
	util.AddNetworkString("ulx_sendprofile")
end

if CLIENT then
	net.Receive("ulx_sendprofile", function()
		local targ_ply = net.ReadEntity()
		if !IsValid(targ_ply) then return end
		targ_ply:ShowProfile()
	end)
end

function ulx.profile(calling_ply, target_ply)
	net.Start("ulx_sendprofile")
		net.WriteEntity(target_ply)
	net.Send(calling_ply)
end
local profile = ulx.command("Information", "ulx profile", ulx.profile, "!profile", true)
profile:addParam{type=ULib.cmds.PlayerArg}
profile:defaultAccess(ULib.ACCESS_ADMIN)
profile:help("Opens steam profile of target.")

if SERVER then
	util.AddNetworkString("ulx_getfriends")
	util.AddNetworkString("ulx_sendfriends")

	net.Receive("ulx_sendfriends", function(l, ply)
		if !ply.sending_friends then return end
		ply.sending_friends = nil
		local friends = net.ReadTable()
		local friendstring = table.concat(friends, ", ")
		if string.len(friendstring) == 0 then
			friendstring = "none"
		end
		local user = net.ReadEntity()
		if IsValid(user) and user:IsPlayer() and user.requesting_friends then
			user.requesting_friends = nil
			user:ChatPrint(ply:Name().." is friends with: "..friendstring..".")
		end
	end)
end

if CLIENT then
	net.Receive("ulx_getfriends", function(len, ply)
		local user = net.ReadEntity()
		if !IsValid(user) then return end
		local friends = {}
		for _,v in ipairs(player.GetAll()) do
			if v:GetFriendStatus() == "friend" then
				table.insert(friends, v:Name())
			end
		end
		if IsValid(user) and user:IsPlayer() then
			net.Start("ulx_sendfriends")
				net.WriteTable(friends)
				net.WriteEntity(user)
			net.SendToServer()
		end
	end)
end

function ulx.listfriends(calling_ply, target_ply)
	if !IsValid(calling_ply) then
		Msg("This command can't be used from console, sorry!\n" )
		return
	end
	calling_ply.requesting_friends = true
	target_ply.sending_friends = true
	net.Start("ulx_getfriends")
		net.WriteEntity(calling_ply)
	net.Send(target_ply)
end
local listfriends = ulx.command("Information", "ulx listfriends", ulx.listfriends, "!listfriends",true)
listfriends:addParam{type=ULib.cmds.PlayerArg}
listfriends:defaultAccess(ULib.ACCESS_ADMIN)
listfriends:help("Shows target's friends playing on the server.")

function ulx.showtime(calling_ply, target_ply)
	if IsValid(calling_ply) then
		calling_ply:ChatPrint("ID: "..target_ply:SteamID())
		calling_ply:ChatPrint("Total time: "..UTime_TimeToString(target_ply:GetUTimeTotalTime()))
		calling_ply:ChatPrint("Current time: "..UTime_TimeToString(target_ply:GetUTimeSessionTime()))
	else
		ULib.console(calling_ply, "ID: "..target_ply:SteamID())
		ULib.console(calling_ply, "Total time: "..UTime_TimeToString(target_ply:GetUTimeTotalTime()))
		ULib.console(calling_ply, "Current time: "..UTime_TimeToString(target_ply:GetUTimeSessionTime()))
	end
end
local showtime = ulx.command("Information", "ulx showtime", ulx.showtime, "!showtime")
showtime:addParam{type=ULib.cmds.PlayerArg}
showtime:defaultAccess(ULib.ACCESS_ADMIN)
showtime:help("Shows total and current playtime of target.")

function ulx.timeid(calling_ply, steamid)
	steamid = steamid:upper()
	if !ULib.isValidSteamID(steamid) then
		ULib.tsayError(calling_ply, "Invalid steamid.")
		return
	end
	local target_ply = player.GetBySteamID(steamid)
	if IsValid(target_ply) then
		ulx.showtime(calling_ply, target_ply)
		return
	end
	local is_ply = IsValid(calling_ply)
	ULib.query("SELECT totaltime FROM utime WHERE steamid = '"..steamid.."'", function(result)
		if is_ply then
			if IsValid(calling_ply) then
				calling_ply:ChatPrint("ID: "..steamid)
				calling_ply:ChatPrint("Total time: "..UTime_TimeToString(result and result[1].totaltime or 0))
			end
		else
			ULib.console(calling_ply, "ID: "..steamid)
			ULib.console(calling_ply, "Total time ("..steamid.."): "..UTime_TimeToString(result and result[1].totaltime or 0))
		end
	end)
end
local timeid = ulx.command("Information", "ulx timeid", ulx.timeid, "!timeid")
timeid:addParam{type=ULib.cmds.StringArg, hint="steamid"}
timeid:defaultAccess(ULib.ACCESS_ADMIN)
timeid:help("Show total playtime of target using their steamid.")

local sql_prefix = "ulx_activity"
if SERVER then
	sql_prefix = CreateConVar("ulx_activity_sqlprefix", sql_prefix, FCVAR_ARCHIVE)

	local two_weeks = 14 * 24 * 60 * 60

	local function ResetOldActivity()
		ULib.query("DELETE FROM "..sql_prefix:GetString().."_time WHERE `i_date` < "..(os.time() - two_weeks))
	end

	local function UpdateActivityPlayer(ply, time_update, firstjoin)
		if !IsValid(ply) then return end
		local sid = ply:SteamID()
		local os_time = os.time()
		local cur_time = os.date("%d.%m.%Y", os_time)
		ULib.query("REPLACE INTO "..sql_prefix:GetString().."_player VALUES('"..sid.."', '"..cur_time.."')")
		if time_update then
			ULib.query("SELECT length, away FROM "..sql_prefix:GetString().."_time WHERE `steamid` = '"..sid.."' AND `date` = '"..cur_time.."'", function(result)
				if !IsValid(ply) then return end
				if !result then
					ULib.query("INSERT INTO "..sql_prefix:GetString().."_time VALUES('"..sid.."', '"..cur_time.."', "..os_time..", 0, 0)")
				elseif !firstjoin then
					local length = tonumber(result[1].length)
					local away = tonumber(result[1].away)
					local is_away = ply.getDarkRPVar and ply:getDarkRPVar("AFK") or ply.GetForceSpec and ply:GetForceSpec() or ply.afk
					if is_away then
						ULib.query("UPDATE "..sql_prefix:GetString().."_time SET `i_date` = "..os_time..", `length` = "..(length + time_update)..", `away` = "..(away + (is_away and time_update or 0)).." WHERE `steamid` = '"..sid.."' AND `date` = '"..cur_time.."'")
					else
						ULib.query("UPDATE "..sql_prefix:GetString().."_time SET `i_date` = "..os_time..", `length` = "..(length + time_update).." WHERE `steamid` = '"..sid.."' AND `date` = '"..cur_time.."'")
					end
				end
			end)
		end
	end

	hook.Add("ULibDatabaseInitialized", "ULX_InitActivity", function()
		ULib.query("CREATE TABLE IF NOT EXISTS "..sql_prefix:GetString().."_player (`steamid` varchar(255) PRIMARY KEY NOT NULL, `lastseen` varchar(255) NOT NULL)")
		ULib.query("CREATE TABLE IF NOT EXISTS "..sql_prefix:GetString().."_time (`steamid` varchar(255) NOT NULL, `date` varchar(255) NOT NULL, `i_date` INT(32) NOT NULL, `length` INT(32) NOT NULL, `away` INT(32) NOT NULL)")
		ULib.query("CREATE INDEX IF NOT EXISTS IDX_ULX_ACTIVITY_TIME_STEAMID ON "..sql_prefix:GetString().."_time (`steamid`)")
		ULib.query("CREATE INDEX IF NOT EXISTS IDX_ULX_ACTIVITY_TIME_DATE ON "..sql_prefix:GetString().."_time (`date`)")

		for _, v in ipairs(player.GetAll()) do
			UpdateActivityPlayer(v)
		end

		ResetOldActivity()
	end)

	hook.Add("PlayerInitialSpawn", "ULX_TrackActivity", function(ply)
		UpdateActivityPlayer(ply, true, true)
	end)

	hook.Add("UTime_UpdatePlayer", "ULX_TrackActivity", function(ply, total, subtract)
		UpdateActivityPlayer(ply, subtract)
	end)
end

local function PrintPlayerActivity(calling_ply, sid, log)
	local is_ply = IsValid(calling_ply)
	if isnumber(sid) then
		ULib.query("SELECT * FROM "..sql_prefix:GetString().."_time", function(result)
			if is_ply and !IsValid(calling_ply) then return end
			local time_tbl = {}
			local away_tbl = {}
			for _, v in ipairs(result or {}) do
				local ply_sid = v.steamid
				time_tbl[ply_sid] = time_tbl[ply_sid] and time_tbl[ply_sid] + tonumber(v.length) or tonumber(v.length)
				away_tbl[ply_sid] = away_tbl[ply_sid] and away_tbl[ply_sid] + tonumber(v.away) or tonumber(v.away)
			end
			table.sort(time_tbl, function(a, b) return a > b end)
			if is_ply and IsValid(calling_ply) then
				calling_ply:ChatPrint("Check your console.")
			end
			local place = 0
			for k, v in SortedPairsByValue(time_tbl, true) do
				place = place + 1
				local length = v
				if length == 0 then
					length = "under 60 seconds"
				else
					length = ULib.secondsToStringTime(length)
				end
				local away = away_tbl[k]
				local was_away = away > 0
				if was_away then
					away = ULib.secondsToStringTime(away)
				end
				ULib.console(calling_ply, place..":")
				ULib.console(calling_ply, "	"..k.." - "..length..(was_away and " (afk for "..away..")" or ""))
				if place == sid then
					break
				end
			end
		end)
		return
	end
	ULib.query("SELECT lastseen FROM "..sql_prefix:GetString().."_player WHERE `steamid` = '"..sid.."'", function(lastseen)
		if is_ply and !IsValid(calling_ply) then return end
		if lastseen then
			lastseen = lastseen[1].lastseen
			ULib.query("SELECT * FROM "..sql_prefix:GetString().."_time WHERE `steamid` = '"..sid.."'", function(result)
				if is_ply and !IsValid(calling_ply) then return end
				if is_ply and IsValid(calling_ply) then
					calling_ply:ChatPrint("ID: "..sid)
					calling_ply:ChatPrint("Last activity: "..lastseen)
				else
					ULib.console(calling_ply, "ID: "..sid)
					ULib.console(calling_ply, "Last activity: "..lastseen)
				end
				local total_time
				local away_time
				if result then
					table.sort(result, function(a, b) return a.i_date < b.i_date end)
					for _, v in ipairs(result) do
						local length = tonumber(v.length)
						total_time = total_time or 0
						total_time = total_time + length
						local away = tonumber(v.away)
						if away > 0 then
							away_time = away_time or 0
							away_time = away_time + away
						end
					end
				end
				if !total_time then
					total_time = "none"
				elseif total_time == 0 then
					total_time = "under 60 seconds"
				else
					total_time = ULib.secondsToStringTime(total_time)
				end
				if away_time then
					away_time = ULib.secondsToStringTime(away_time)
				end
				if is_ply and IsValid(calling_ply) then
					calling_ply:ChatPrint("Activity in last two weeks: "..total_time..(away_time and " (afk for "..away_time..")" or ""))
				else
					ULib.console(calling_ply, "Activity in last two weeks: "..total_time..(away_time and " (afk for "..away_time..")" or ""))
				end
				if log then
					if is_ply and IsValid(calling_ply) then
						calling_ply:ChatPrint("Check your console for the online log.")
					end
					ULib.console(calling_ply, "Online times for "..sid)
					if result then
						for _, v in ipairs(result) do
							local date = v.date
							local length = tonumber(v.length)
							if length == 0 then
								length = "under 60 seconds"
							else
								length = ULib.secondsToStringTime(length)
							end
							local away = tonumber(v.away)
							local was_away = away > 0
							if was_away then
								away = ULib.secondsToStringTime(away)
							end
							ULib.console(calling_ply, date..": "..length..(was_away and " (afk for "..away..")" or ""))
						end
					else
						ULib.console(calling_ply, "none")
					end
				end
			end)
		else
			ULib.tsayError(calling_ply, "Player not registered.")
		end
	end)
end

function ulx.activitylist(calling_ply, num)
	PrintPlayerActivity(calling_ply, num)
end
local activitylist = ulx.command("Information", "ulx activitylist", ulx.activitylist, "!activitylist")
activitylist:addParam{type=ULib.cmds.NumArg, default = 25, min = 1, max = 100, hint="Max players", ULib.cmds.round, ULib.cmds.optional}
activitylist:defaultAccess(ULib.ACCESS_SUPERADMIN)
activitylist:help("Shows most active players of last two weeks.")

function ulx.activity(calling_ply, target_ply, bool)
	if !IsValid(target_ply) then
		PrintPlayerActivity(calling_ply)
		return 
	end
	PrintPlayerActivity(calling_ply, target_ply:SteamID(), bool)
end
local activity = ulx.command("Information", "ulx activity", ulx.activity, "!activity")
activity:addParam{type=ULib.cmds.PlayerArg}
activity:addParam{type=ULib.cmds.BoolArg, hint="Show online logs?", ULib.cmds.optional}
activity:defaultAccess(ULib.ACCESS_SUPERADMIN)
activity:help("Shows last activity, play time and presumed afk time of last 2 weeks.")

function ulx.activityid(calling_ply, steamid, bool)
	steamid = steamid:upper()
	if !ULib.isValidSteamID(steamid) then
		ULib.tsayError(calling_ply, "Invalid steamid.")
		return
	end
	PrintPlayerActivity(calling_ply, steamid, bool)
end
local activityid = ulx.command("Information", "ulx activityid", ulx.activityid, "!activityid")
activityid:addParam{type=ULib.cmds.StringArg, hint="steamid"}
activityid:addParam{type=ULib.cmds.BoolArg, hint="Show online logs?", ULib.cmds.optional}
activityid:defaultAccess(ULib.ACCESS_SUPERADMIN)
activityid:help("Shows last activity, play time and presumed afk time of last 2 weeks using steamid.")

function ulx.pdata(calling_ply, target_ply, bool)
	if IsValid(calling_ply) then
		calling_ply:ChatPrint("ID: "..target_ply:SteamID())
		calling_ply:ChatPrint("RP-Name: "..target_ply:Name())
		calling_ply:ChatPrint("Wallet: "..DarkRP.formatMoney(target_ply:getDarkRPVar("money") or 0))
	else
		ULib.console(calling_ply, "ID: "..target_ply:SteamID())
		ULib.console(calling_ply, "RP-Name: "..target_ply:Name())
		ULib.console(calling_ply, "Wallet: "..DarkRP.formatMoney(target_ply:getDarkRPVar("money") or 0))
	end
	if bool and IsValid(calling_ply) then
		calling_ply:SendLua([[player.GetBySteamID(targ_ply:SteamID):ShowProfile()]])
	end
end
local pdata = ulx.command("Information", "ulx pdata", ulx.pdata, "!pdata")
pdata:addParam{type=ULib.cmds.PlayerArg}
pdata:addParam{type=ULib.cmds.BoolArg, hint="Open steam profile?", ULib.cmds.optional}
pdata:defaultAccess(ULib.ACCESS_ADMIN)
pdata:help("Shows wallet, name and rpname of target.")

function ulx.pdataid(calling_ply, steamid, bool)
	steamid = steamid:upper()
	if !ULib.isValidSteamID(steamid) then
		ULib.tsayError(calling_ply, "Invalid steamid.")
		return
	end
	local target_ply = player.GetBySteamID(steamid)
	if IsValid(target_ply) then
		ulx.pdata(calling_ply, target_ply)
		return
	end
	local is_ply = IsValid(calling_ply)
	DarkRP.offlinePlayerData(steamid, function(result)
		if is_ply and !IsValid(calling_ply) then return end
		result = result and result[1]
		if !result then
			ULib.tsayError(calling_ply, "Player not found.")
			return
		end
		if IsValid(calling_ply) then
			calling_ply:ChatPrint("ID: "..steamid)
			calling_ply:ChatPrint("RP-Name: "..result.rpname)
			calling_ply:ChatPrint("Wallet: "..DarkRP.formatMoney(tonumber(result.wallet)))
		else
			ULib.console(calling_ply, "ID: "..steamid)
			ULib.console(calling_ply, "RP-Name: "..result.rpname)
			ULib.console(calling_ply, "Wallet: "..DarkRP.formatMoney(tonumber(result.wallet)))
		end
	end)
	if bool and IsValid(calling_ply) then
		calling_ply:SendLua("gui.OpenURL('https://steamcommunity.com/profiles/"..util.SteamIDTo64(steamid).."')")
	end
end
local pdataid = ulx.command("Information", "ulx pdataid", ulx.pdataid, "!pdataid")
pdataid:addParam{type=ULib.cmds.StringArg, hint="steamid"}
pdataid:addParam{type=ULib.cmds.BoolArg, hint="Open steam profile?", ULib.cmds.optional}
pdataid:defaultAccess(ULib.ACCESS_SUPERADMIN)
pdataid:help("Shows wallet, name and rpname of target using their steamid.")