include("nlr_config.lua")

NLR.DeathZones = NLR.DeathZones or {}

surface.CreateFont("NLR_NormalFont", {font = "Arial", size = 30, antialias = true})
surface.CreateFont("NLR_MonsterFont", {font = "Arial", size = 160, weight = 500, antialias = true})

local use_font = system.IsWindows() and "Tahoma" or "Verdana"
surface.CreateFont("NLR_Timer", {font = use_font, size = 22, weight = 1000, blursize = 0, scanlines = 0, antialias = true})

local local_ply
local nlr_timer = CreateClientConVar("cl_nlr_timer", 1, FCVAR_ARCHIVE)

local circlecomplexity = CreateClientConVar("cl_nlr_circlecomplexity", 50, FCVAR_ARCHIVE)

local sphere = CreateClientConVar("cl_nlr_sphere", 1, FCVAR_ARCHIVE)
local spherecomplexity = CreateClientConVar("cl_nlr_spherecomplexity", 35, FCVAR_ARCHIVE)

local draw, surface, render, cam = draw, surface, render, cam

local isGhost = false

hook.Add("OnContextMenuOpen", "NLR_DisableContextMenu", function()
	if isGhost then
		return false
	end
end)

local function DrawZoneInfo()
	local_ply = local_ply or LocalPlayer()
	local boxheight = 75
	local timer = NLR.nlrtimer
	if timer then
		boxheight = 100
	end
	local scrw2 = ScrW() / 2
	draw.RoundedBox(0, scrw2 - 300, 100, 600, boxheight, NLR.ghosttextboxcolor)
	draw.DrawText("NLR - Bitte entferne dich von deinem Todesort!", "NLR_NormalFont", scrw2, 120, NLR.ghosttextcolor, TEXT_ALIGN_CENTER)
	if timer then
		local timeleft = 0
		local zdist = math.huge
		local pos = local_ply:EyePos()
		for _, v in pairs(NLR.DeathZones) do
			local dist = pos:DistToSqr(v["pos"])
			if zdist > dist then
				zdist = dist
				timeleft = v["time"]
			end
		end
		local time = math.Round(math.max((timeleft + NLR.nlrtime) - CurTime(), 0))
		draw.DrawText("Diese NLR-Zone verschwindet in "..string.ToMinutesSeconds(time).." min.", "NLR_NormalFont", scrw2, 150, NLR.ghosttextcolor, TEXT_ALIGN_CENTER)
	end
end

local grave = "- Du bist hier gestorben -"
local dimension = NLR.distancetoscene / 3
local markangle = 0

local cachedCircles = {}
local function draw_Circle(x, y, radius, seg, identifier)
	if !cachedCircles[identifier] or cachedCircles[identifier][2] != seg	then
		local cir = {}
		table.insert(cir, {x = x, y = y, u = 0.5, v = 0.5})
		for i = 0, seg do
			local a = math.rad((i / seg) * -360)
			table.insert(cir, {x = x + math.sin(a) * radius, y = y + math.cos(a) * radius, u = math.sin(a) / 2 + 0.5, v = math.cos(a) / 2 + 0.5})
		end
		local a = math.rad(0)
		table.insert(cir, {x = x + math.sin(a) * radius, y = y + math.cos(a) * radius, u = math.sin(a) / 2 + 0.5, v = math.cos(a) / 2 + 0.5})

		cachedCircles[identifier] = {cir, seg}
	end

	surface.DrawPoly(cachedCircles[identifier][1])
end

local cachedCircleTraces = {}

local nlr_circle_color = Color(125, 0, 0, 255)
local vector_50, vector_5, vector_10, lookVector = Vector(0, 0, 60), Vector(0, 0, 8), Vector(0, 0, 10), Vector(0, 0, 1)
local color_special, color_red = Color(255, 0, 0, 100), Color(255, 0, 0, 50)

local drawDistance = 3000 * 3000

local product
local function IsInFront(local_ply, pos, shoot_pos, direction)
	product = (pos.x - shoot_pos.x) * direction.x + (pos.y - shoot_pos.y) * direction.y + (pos.z - shoot_pos.z) * direction.z
	return product < 0
end

local function Draw3D2D(depth, sky)
	if depth or sky then return end

	if table.IsEmpty(NLR.DeathZones) then
		hook.Remove("RenderScreenspaceEffects", "NLR_ColorModify")
		return
	end

	local_ply = local_ply or LocalPlayer()

	local curTime = CurTime()
	local eyePos = local_ply:EyePos()

	for _, v in pairs(NLR.DeathZones) do
		markangle = curTime * 50
		local pos = v["pos"]
		if eyePos:DistToSqr(pos) <= drawDistance then
			if sphere:GetBool() then
				local spherecomplexity = math.Clamp(spherecomplexity:GetInt() - 10, 10, 90)
				render.DrawWireframeSphere(pos, NLR.distancetoscene, spherecomplexity, spherecomplexity, nlr_circle_color, true)
			else
				local circlecomplexity = math.Clamp(circlecomplexity:GetInt(), 10, 100)
				local vec = pos + vector_5

				if IsInFront(local_ply, vec, local_ply:GetShootPos(), lookVector) then
					cam.Start3D2D(vec, angle_zero, 3)
						surface.SetDrawColor(isGhost and color_special or color_red)
						draw.NoTexture()
						draw_Circle(0, 0, dimension, circlecomplexity, v.id)
					cam.End3D2D()
				else
					cam.Start3D2D(vec, Angle(180, 0, 0), 3)
						surface.SetDrawColor(isGhost and color_special or color_red)
						draw.NoTexture()
						draw_Circle(0, 0, dimension, circlecomplexity, v.id)
					cam.End3D2D()
				end
			end

			local vec = vector_50
			vec = pos + vec

			cam.Start3D2D(vec, Angle(0, markangle, 90), 0.1)
				draw.DrawText(grave, "NLR_MonsterFont", 5, 5, NLR.deathmarkcolor, TEXT_ALIGN_CENTER)
			cam.End3D2D()
			cam.Start3D2D(vec, Angle(0, markangle - 180, 90), 0.1)
				draw.DrawText(grave, "NLR_MonsterFont", 5, 5, NLR.deathmarkcolor, TEXT_ALIGN_CENTER)
			cam.End3D2D()
		end
	end
end

local cm = {}
cm["$pp_colour_brightness"] = -0.05
cm["$pp_colour_contrast"] = 1
cm["$pp_colour_addr"] = 0
cm["$pp_colour_addg"] = 0
cm["$pp_colour_addb"] = 0
cm["$pp_colour_mulr"] = 0
cm["$pp_colour_mulg"] = 0
cm["$pp_colour_mulb"] = 0
cm["$pp_colour_colour"] = 0

local function ColorModify()
	DrawColorModify(cm)
end

hook.Add("NLR_GhostState", "NLR_AddHooks", function(state)
	isGhost = state

	if state then
		hook.Add("HUDPaint", "NLR_ZoneNotifiy", DrawZoneInfo)
		hook.Add("RenderScreenspaceEffects", "NLR_ColorModify", ColorModify)
	else
		hook.Remove("HUDPaint", "NLR_ZoneNotifiy")
		hook.Remove("RenderScreenspaceEffects", "NLR_ColorModify")
	end
end)

local nlrtime
local nlr_addtime = 0

local width = 150
local function DrawTimer()
	if !nlr_timer:GetBool() or !nlrtime or nlrtime - CurTime() < -4 then
		hook.Remove("HUDPaint", "NLR_DrawTimer")
		return
	end
	local scrw, scrh = ScrW(), ScrH()
	if nlrtime - CurTime() < 0 then
		draw.SimpleTextOutlined("Deine NLR ist abgelaufen!", "NLR_Timer", scrw / 2, scrh - 186, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
	else
		draw.RoundedBox(0, (scrw - width) / 2,  scrh - 212, width, 50, Color(0, 0, 0, 200))
		draw.SimpleTextOutlined("NLR-Timer:", "NLR_Timer", scrw / 2, scrh - 210, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
		draw.SimpleTextOutlined("_____________", "NLR_Timer", scrw / 2, scrh - 206, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
		draw.SimpleTextOutlined(string.ToMinutesSeconds(math.ceil(math.max(nlrtime - CurTime()))), "NLR_Timer", scrw / 2, scrh - 186, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, color_black)
	end
end

net.Receive("NLR_AddNLR", function()
	local zone = net.ReadTable()
	nlr_addtime = zone.add or 0
	zone.add = nil
	table.insert(NLR.DeathZones, zone)
	local time = zone.time
	if NLR.displaynlrtimer then
		nlrtime = time + NLR.nlrtime
		hook.Add("HUDPaint", "NLR_DrawTimer", DrawTimer)
		hook.Add("PostDrawTranslucentRenderables", "NLR_Draw3D2D", Draw3D2D)
	end
end)

net.Receive("NLR_RemoveCertainZone", function()
	local id = net.ReadInt(16)
	for k, zones in pairs(NLR.DeathZones) do
		if zones["id"] == id then
			NLR.DeathZones[k] = nil

			cachedCircles[zones["id"]] = nil
			cachedCircleTraces[zones["id"]] = nil
			break
		end
	end
end)

net.Receive("NLR_RemoveNLRZones", function()
	NLR.DeathZones = {}
	nlrtime = CurTime()

	cachedCircles = {}
	cachedCircleTraces = {}
end)

local NFrame
net.Receive("NLR_AddMessage", function()
	if !IsValid(NFrame) or !IsValid(NFrame.NPanel) then return end
	NFrame.NPanel.ExtraMessage = net.ReadString()
end)

local function NLR_DrawBox()
	if IsValid(NFrame) then return end
	NFrame = vgui.Create("DFrame")
	NFrame:SetSize(600, nlr_addtime > 0 and 200 or 160)
	NFrame:Center()
	NFrame:SetTitle("NLR - New Life Rule")
	NFrame:SetBackgroundBlur(true)
	NFrame:SetVisible(true)
	NFrame:SetDraggable(false)
	NFrame:ShowCloseButton(false)
	NFrame:MakePopup()
	NFrame:ParentToHUD()
	NFrame.NextThink = CurTime() + 2
	local ply = LocalPlayer()
	local oldThink = NFrame.Think
	NFrame.Think = function(self)
		if NFrame.NextThink <= CurTime() then
			if ply:Alive() or ply:getDarkRPVar("AFK") then
				NFrame:Remove()
			end
		end
		oldThink(self)
	end
	local oldPaint = NFrame.Paint
	NFrame.Paint = function(s, w, h)
		if s.m_bBackgroundBlur then
			Derma_DrawBackgroundBlur(s, s.m_fCreateTime)
		end
		draw.RoundedBox(0, 0, 0, w, 24, Color(30, 30, 30, 255))
		draw.RoundedBox(0, 0, 23, w, 1, Color(150, 20, 20, 255))
		draw.RoundedBox(0, 0, 24, w, h - 24, Color(50, 50, 50, 240))
	end
	local NPanel = vgui.Create("DPanel", NFrame)
	NFrame.NPanel = NPanel
	NPanel:SetSize(NFrame:GetWide() - 20, NFrame:GetTall() - 40)
	NPanel:SetPos(10, 30)
	NPanel.Paint = function(self, w, h)
		surface.SetDrawColor(40, 40, 40, 200)
		surface.DrawRect(0, 0, w, h)
		draw.SimpleText("Du bist gestorben und hast alles vergessen, was in Zusammenhang mit deinem Tod steht.", "DermaDefault", w / 2, 20, Color(225, 225, 225), TEXT_ALIGN_CENTER)
		draw.SimpleText("Du darfst deinen Todesort für die nächsten "..(NLR.nlrtime / 60).." Minuten nicht erneut betreten!", "DermaDefault", w / 2, 35, Color(225, 225, 225), TEXT_ALIGN_CENTER)
		if self.ExtraMessage then
			draw.SimpleText(self.ExtraMessage, "DermaDefault", w / 2, 50, Color(225, 125, 125), TEXT_ALIGN_CENTER)
		end
		if nlr_addtime > 0 then
			draw.SimpleText("Wenn du innerhalb 10 Minuten deines letzten Todes erneut stirbst, erhöht sich deine nächste NLR um eine Minute.", "DermaDefault", w / 2, 140, Color(225, 225, 225), TEXT_ALIGN_CENTER)
		end
	end
	local NButton = vgui.Create("DButton", NFrame)
	NButton:SetPos(210, 105)
	NButton:SetText("Bitte warte...")
	NButton:SetFont("Trebuchet24")
	NButton:SetTextColor(Color(50, 50, 50))
	NButton:SetSize(180, 30)
	NButton.Paint = function(self, w, h)
		if self:GetDisabled() then
			surface.SetDrawColor(0, 110, 160)
			surface.DrawRect(0, 0, w, h)
		else
			surface.SetDrawColor(0, 100, 160)
			surface.DrawRect(0, 0, w, h)
		end
	end
	NButton:SetDisabled(true)
	NButton.DoClick = function(self)
		if self:GetDisabled() then
			return
		else
			net.Start("NLR_Respawn")
			net.SendToServer()
			NFrame:Remove()
		end
	end
	local waitTime = 5
	local cur = CurTime()
	NButton.Think = function(self)
		if cur < CurTime() - waitTime then
			self:SetDisabled(false)
			self:SetText("Verstanden!")
		else
			self:SetText("Bitte warte "..math.Round(math.abs(CurTime() - cur - waitTime)).."s")
		end
	end
	if nlr_addtime > 0 then
		local DeathPenalties = vgui.Create("DPanel", NFrame)
		DeathPenalties:SetPos(250, 140)
		DeathPenalties:SetSize(100, 20)
		DeathPenalties.Paint = function(self, w, h)
			surface.SetDrawColor(0, 86, 125)
			surface.DrawRect(0, 0, w, h)
			draw.SimpleText("Todesstrafe: "..string.Comma(nlr_addtime).."s", "Default", w / 2, 4, Color(35, 35, 35), TEXT_ALIGN_CENTER)
		end
	end
end

net.Receive("NLR_DrawBox", function()
	NLR_DrawBox()
end)