--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| 	Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]


local PLUGIN = PLUGIN

local datafields = {"genericdata", "datafilelogs", "datafileviolations", "datafilemedicalrecords"}

function PLUGIN:SendFile(client, file)
	timer.Simple(0.05, function()
		netstream.Start(client, "OpenDatafileCl", file)
	end)
end

-- Include new required data to datafiles of old characters
function PLUGIN:UpdateOldVortData(character, genericdata)
	if (!character or !istable(genericdata)) then return end

	genericdata.collarID  = character:GetCollarID() or "N/A"
	genericdata.cohesionPoints = genericdata.socialCredits or 0
	genericdata.cohesionPointsDate = ix.config.Get("day").."/"..ix.config.Get("month").."/"..ix.config.Get("year")
	genericdata.nulled = "INACTIVE"
	genericdata.cid = "N/A"
	genericdata.name = nil

	if (character:HasFlags("N") or character:GetBackground() == "Collaborator") then
		genericdata.nulled = "ACTIVE"
	end

	for _, v in pairs(character:GetInventory():GetItems()) do
		if (table.HasValue({"Vortigaunt Collar", "Vortigaunt Collar (fake)"}, v.name) and v:GetData("equip") == true) then
			if (v:GetData("collarID", nil) and v:GetData("sterilizedCredits", nil)) then
				genericdata.cohesionPoints = v:GetData("sterilizedCredits", 0)
			end
		end
	end

	character:SetGenericdata(genericdata)
	character:Save()

	character:GetPlayer():Notify("New format successfully applied to your datafile.")
end

-- Search the collarID through the database
function PLUGIN:LookUpCollarID(client, id, bNotify)
	if (!client or !id) then return end

	id = string.sub(id, 2)

	local query = mysql:Select("ix_characters")
	query:Select("name")
	query:Select("faction")
	query:Select("id")
	query:Select("collarID")
	query:Select("background")
	query:Where("collarID", id)
	query:Where("schema", Schema and Schema.folder or "helix")
	query:Callback(function(result)
		if (!istable(result) or #result == 0) then
			return
		end

		local resultFactionString = result[1].faction

		if (resultFactionString != "vortigaunt") then
			return
		end

		local dataSelect = mysql:Select("ix_characters_data")
		dataSelect:Where("id", result[1].id)
		dataSelect:WhereIn("key", datafields)
		dataSelect:Callback(function(dataSelectResult)
			if (!istable(dataSelectResult) or #dataSelectResult == 0) then
				return
			end

			local file = {}
			for _, v in ipairs(dataSelectResult) do
				file[v.key] = util.JSONToTable(v.data or "")
				file["charID"] = result[1].id

				if (v.key == "genericdata") then
					if file[v.key].name != result[1].name then
						file[v.key].name = result[1].name

						local updateQuery = mysql:Update("ix_characters_data")
						updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
						updateQuery:Where("id", result[1].id)
						updateQuery:Where("key", "genericdata")
						updateQuery:Execute()
					end
				end
			end

			if (bNotify) then
				local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())

				ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset:") .. " #" .. result[1].collarID)
			end

			self:SendFile(client, file)
		end)
		dataSelect:Execute()

	end)
	query:Execute()
end

function PLUGIN:RefreshDatafile(client, id, bIsLocal, bCachedID, bNotify)
	if !client then return end

	if (client:Team() == FACTION_SERVERADMIN) then
		bNotify = false
	end

	--If the player is trying to view his/her own datafile
	if (bIsLocal) then
		local character = client:GetCharacter()
		local file = {}

		file["genericdata"] = character:GetGenericdata()
		file["datafileviolations"] = character:GetDatafileviolations()
		file["datafilemedicalrecords"] = character:GetDatafilemedicalrecords()
		file["datafilelogs"] = character:GetDatafilelogs()
		file["charID"] = character:GetID()

		if character:IsVortigaunt() and !file["genericdata"].cohesionPoints then
			self:UpdateOldVortData(character, file["genericdata"])
		end

		self:SendFile(client, file)

		return
	end

	local target = false

	if (bCachedID) then
		if isnumber(tonumber(id)) then
			if ix.char.loaded[id] then
				target = ix.char.loaded[id]
			end
		end
	end

	if !target then
		-- Check for cached characters
		if (tonumber(id) != nil and string.utf8len(tostring(id)) <= 5) then
			-- id to cid comparison
			for _, v in pairs(ix.char.loaded) do
				local cid = v.GetCid and v:GetCid()
				local genericdata = v:GetGenericdata()

				if (v:IsVortigaunt() and v:GetCid() == id and genericdata.cid == "N/A") then return end

				if (cid and id) then
					if (tostring(cid) == id) then
						target = v
						break
					end
				end
			end
		elseif (id != nil and string.sub(id, 1, 1) == "!") then
			id = string.sub(id, 2)

			for _, v in pairs(ix.char.loaded) do
				if (v:IsVortigaunt() and v:GetCollarID() == id) then
					target = v
					break
				end
			end
		else
			-- id to name comparison
			for _, v in pairs(ix.char.loaded) do
				local genericdata = v:GetGenericdata()

				if string.find(v:GetName(), id) then
					if (v:IsVortigaunt() and genericdata.cid == "N/A") then return end

					target = v
					break
				end
			end
		end
	end

    -- Make sure further code isn't ran
    if target then
        local file = {}
        file["genericdata"] = target:GetGenericdata()
        file["datafileviolations"] = target:GetDatafileviolations()
        file["datafilemedicalrecords"] = target:GetDatafilemedicalrecords()
        file["datafilelogs"] = target:GetDatafilelogs()
		file["charID"] = target:GetID()

		if (target:IsVortigaunt() and !file["genericdata"].cohesionPoints) then
			self:UpdateOldVortData(target, file["genericdata"])
		end

		if (bNotify) then
			local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())

			if (target:IsVortigaunt()) then
				if (file["genericdata"].cid == "N/A" and file["genericdata"].collarID != "N/A") then
					ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset collar:") .. " #" .. target:GetCollarID())
				elseif (file["genericdata"].cid == "N/A" and file["genericdata"].collarID == "N/A") then
					ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset collar:") .. " #" .. target:GetFakeCollarID())
				else
					ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on " .. string.upper("biotic asset identification card:") .. " #" .. file["genericdata"].cid)
				end
			else
				ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(target:GetName()) .. "', #" .. target:GetCid())
			end
		end

        self:SendFile(client, file)
        return
    end

	-- If no cached character, search in datafile
	if (tonumber(id) != nil and string.utf8len( id ) <= 5) then
		local query = mysql:Select("ix_characters")
		query:Select("name")
		query:Select("faction")
		query:Select("id")
		query:Select("cid")
		query:Select("background")
		query:Where("cid", id)
		query:Where("schema", Schema and Schema.folder or "helix")
		query:Callback(function(result)
			if (!istable(result) or #result == 0) then
				return
			end

			local resultFactionString = result[1].faction
			if (resultFactionString == "overwatch" and client:Team() != FACTION_OVERWATCH) then
				client:NotifyLocalized("You do not have access to this datafile!")
				return false
			end
			if (resultFactionString == "ota" or resultFactionString == "administrator" or resultFactionString == "guard") then
				local character = client:GetCharacter()
				if (client:Team() != FACTION_OVERWATCH and client:Team() != FACTION_OTA and character:GetClass() != FACTION_MCP and client:Team() != CLASS_CP_CMD and character:GetClass() != CLASS_CP_CPT and character:GetClass() != CLASS_CP_RL) then
					if client:Team() != FACTION_ADMIN then
						client:NotifyLocalized("You do not have access to this datafile!")
						return false
					end
				end
			end

			local dataSelect = mysql:Select("ix_characters_data")
			dataSelect:Where("id", result[1].id)
			dataSelect:WhereIn("key", datafields)
			dataSelect:Callback(function(dataSelectResult)
				if (!istable(dataSelectResult) or #dataSelectResult == 0) then
					return
				end

				local file = {}
				for _, v in ipairs(dataSelectResult) do
					file[v.key] = util.JSONToTable(v.data or "")
					file["charID"] = result[1].id

					if (v.key == "genericdata") then
						if (resultFactionString == "vortigaunt" and util.JSONToTable(v.data).cid == "N/A") then return end

						if file[v.key].name != result[1].name then
							file[v.key].name = result[1].name

							local updateQuery = mysql:Update("ix_characters_data")
							updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
							updateQuery:Where("id", result[1].id)
							updateQuery:Where("key", "genericdata")
							updateQuery:Execute()
						end
					end
				end

				if (bNotify) then
					local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())

					ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(result[1].name) .. "', #" .. result[1].cid)
				end

				self:SendFile(client, file)
			end)
			dataSelect:Execute()

		end)
		query:Execute()
	else
		if (string.sub(id, 1, 1) == "!") then
			self:LookUpCollarID(client, id, bNotify)
		end

		local query = mysql:Select("ix_characters")
		query:Select("id")
		query:Select("name")
		query:Select("faction")
		query:Select("background")
		query:Select("cid")
		query:WhereLike("name", id)
		query:Where("schema", Schema and Schema.folder or "helix")
		query:Callback(function(result)
			if (!istable(result) or #result == 0) then
				return
			end

			local resultFactionString = result[1].faction
			if (resultFactionString == "overwatch" and client:Team() != FACTION_OVERWATCH) then
				client:NotifyLocalized("You do not have access to this datafile!")
				return false
			end
			if (resultFactionString == "ota" or resultFactionString == "administrator" or resultFactionString == "guard") then
				local character = client:GetCharacter()
				if (client:Team() != FACTION_OVERWATCH and client:Team() != FACTION_OTA and character:GetClass() != FACTION_MCP and client:Team() != CLASS_CP_CMD and character:GetClass() != CLASS_CP_CPT and character:GetClass() != CLASS_CP_RL) then
					if client:Team() != FACTION_ADMIN then
						client:NotifyLocalized("You do not have access to this datafile!")
						return false
					end
				end
			end

			local dataSelect = mysql:Select("ix_characters_data")
			dataSelect:Where("id", result[1].id)
			dataSelect:WhereIn("key", datafields)
			dataSelect:Callback(function(dataSelectResult)
				if (!istable(dataSelectResult) or #dataSelectResult == 0) then
					return
				end

				local file = {}
				for _, v in ipairs(dataSelectResult) do
					file[v.key] = util.JSONToTable(v.data or "")
					file["charID"] = result[1].id

					if (v.key == "genericdata") then
						if (resultFactionString == "vortigaunt" and util.JSONToTable(v.data).cid == "N/A") then return end

						if file[v.key].name != result[1].name then
							file[v.key].name = result[1].name

							local updateQuery = mysql:Update("ix_characters_data")
							updateQuery:Update("data", util.TableToJSON(file[v.key]) or "")
							updateQuery:Where("id", result[1].id)
							updateQuery:Where("key", "genericdata")
							updateQuery:Execute()
						end
					end
				end

				if (bNotify) then
					local author = client:IsDispatch() and "OVERWATCH" or (ix.faction.Get(client:Team()).idInspectionText or "Unit") .. " " .. string.upper(client:GetCombineTag())

					ix.combineNotify:AddNotification("LOG:// " .. author .. " performing identity inspection on '" .. string.upper(result[1].name) .. "', #" .. result[1].cid)
				end
				self:SendFile(client, file)
			end)
			dataSelect:Execute()

		end)
		query:Execute()
	end
end

netstream.Hook("RequestCIDCreditsDatafile", function(client, cid)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end

	cid = Schema:ZeroNumber(cid, 5)
	local housing = ix.plugin.list["housing"]
	if !housing then return end

	housing:LookUpCardItemIDByCID(tostring(cid), function(result)
		local idCardID = result[1].idcard or false
		if !result then return end

		if !ix.item.instances[idCardID] then
			ix.item.LoadItemByID(idCardID, false, function(item)
				if !item then return end
				local credits = item:GetData("credits", 0)
				netstream.Start(client, "UpdateDatafileCredits", credits)
			end)
		else
			local credits = ix.item.instances[idCardID]:GetData("credits", 0)
			netstream.Start(client, "UpdateDatafileCredits", credits)
		end
	end)
end)

netstream.Hook("ixDatafileRequestTransactionLogs", function(client, cid)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end
	cid = Schema:ZeroNumber(cid, 5)

	ix.plugin.list.cid:SelectTransactions(client, "cid", cid, ix.config.Get("TransactionLogDaysDatafile", 14), nil, function(result)
		netstream.Start(client, "ixDatafileReplyTransactionLogs", result)
	end)
end)

netstream.Hook("TerminalReportCrime", function(client, name, cid, text, activeTerminal)
	if !text or !name or !cid then return false end
	if string.len(text) <= 0 then client:Notify("You cannot send an empty crime report.") return end
	if cid != activeTerminal.activeCID then
		return false
	end

	local timestamp = ix.date.GetFormatted("%d.%m.%Y")
	local queryObj = mysql:Insert("ix_crimereports")
		queryObj:Insert("message_poster", name)
		queryObj:Insert("message_text", text)
		queryObj:Insert("message_date", timestamp)
		queryObj:Insert("message_cid", cid)
	queryObj:Execute()

	ix.combineNotify:AddImportantNotification("WRN:// Crime report submitted by " .. name .. " #" .. cid, Color(0, 150, 255), client, activeTerminal:GetPos())
end)

function PLUGIN:GetCrimeReports(client, bArchived, bResolved, curCollect)

    local query = mysql:Select("ix_crimereports")
    query:Select("message_id")
    query:Select("message_text")
    query:Select("message_date")
    query:Select("message_poster")
    query:Select("message_cid")
	query:Callback(function(result)
        if (!istable(result) or #result == 0) then
            return
        end

		local toSort = {}

		for key, _ in pairs(result) do
			local posterIsTable = string.find(result[key].message_poster, "{")
			if posterIsTable then result[key].message_poster = util.JSONToTable(result[key].message_poster) end

			if posterIsTable or (bArchived or bResolved) then
				if bArchived and result[key].message_poster.archived then
					toSort[#toSort + 1] = result[key]

					continue
				end

				if bResolved and result[key].message_poster.resolved then
					toSort[#toSort + 1] = result[key]

					continue
				end

				continue
			end

			toSort[#toSort + 1] = result[key]
		end

		local toSend = {}
		for i = curCollect, curCollect + 5 do
			if toSort[i] then
				toSend[#toSend + 1] = toSort[i]
			end
		end

		netstream.Start(client, "ReplyCrimeReports", toSend)
	end)

    query:Execute()
end

netstream.Hook("GetCrimeReports", function(client, bArchived, bResolved, curCollect)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end

	PLUGIN:GetCrimeReports(client, bArchived, bResolved, curCollect)
end)

netstream.Hook("DeleteCrimeReport", function(client, key, bDatapad, lastUsedTab, curCollect)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end

	local queryObj = mysql:Delete("ix_crimereports")
		queryObj:Where("message_id", key)
	queryObj:Execute()

	PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)

netstream.Hook("ResolveCrimeReport", function(client, key, poster, bUnResolve, lastUsedTab, curCollect)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end

	local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
	ix.combineNotify:AddNotification("NTC:// Crime Report ID #" .. key .. " marked as " .. (bUnResolve and "unresolved" or "resolved") .. " by " .. string.upper(author), Color(171, 222, 47))

	local queryObj = mysql:Update("ix_crimereports")
		queryObj:Where("message_id", key)
		queryObj:Update("message_poster", util.TableToJSON({poster = (istable(poster) and poster.poster or poster), resolved = (!bUnResolve and true or false), archived = (istable(poster) and poster.archived or false)}))
	queryObj:Execute()

	PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)

netstream.Hook("ArchiveCrimeReport", function(client, key, poster, bUnArchive, lastUsedTab, curCollect)
	if (!PLUGIN:HasAccessToDatafile(client)) then return end

	local author = client:IsDispatch() and "Overwatch" or client:GetCombineTag()
	ix.combineNotify:AddNotification("NTC:// Crime Report ID #" .. key .. (bUnArchive and " unarchived" or " archived") .. " by " .. string.upper(author), Color(171, 222, 47))

	local queryObj = mysql:Update("ix_crimereports")
		queryObj:Where("message_id", key)
		queryObj:Update("message_poster", util.TableToJSON({poster = (istable(poster) and poster.poster or poster), resolved = (istable(poster) and poster.resolved or false), archived = (!bUnArchive and true or false)}))
	queryObj:Execute()

	PLUGIN:GetCrimeReports(client, (lastUsedTab == "archived" and true or false), (lastUsedTab == "resolved" and true or false), curCollect)
end)

netstream.Hook("ResetDatafileToDefault", function(client, charID)
	if !CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") then return end
	local character = ix.char.loaded[charID]
	if !character then
		client:NotifyLocalized("The owner of the character needs to be online for the reset to work.")
		return
	end

	local player = character:GetPlayer()
	if !player then return end

	PLUGIN:CreateDatafile(player)
end)