local PlayerTitleColor = Color(255, 153, 153, 255)
local PlayerTitleOutlineColor = Color(0, 0, 0, 200)
local DoorTitleColor = color_white
local DoorTitleOutlineColor = Color(0, 0, 0, 200)
local SellTitleColor = color_white
local SellTitleOutlineColor = Color(0, 0, 0, 200)
local OwnerColor = Color(51, 153, 255, 255)
local OwnerOutlineColor = Color(0, 0, 0, 200)
local CoOwnersColor = Color(153, 255, 255, 255)
local CoOwnersOutlineColor = Color(0, 0, 0, 200)
local AllowedCoOwnersColor = Color(255, 102, 51, 255)
local AllowedCoOwnersOutlineColor = Color(0, 0, 0, 200)
local AllowedTeamsColor = color_white
local AllowedTeamsOutlineColor = Color(0, 0, 0, 200)
local PurchaseColor = color_white
local PurchaseOutlineColor = color_black
local DrawDistance = 300

local FunctioningDoors = {
	["prop_door_rotating"] = true
}

local DisabledDoors = {
	["models/props_c17/door02_double.mdl"] = true,
	["models/erikszeug/rp_ratscity/doppeltuer1.mdl"] = true,
	["models/erikszeug/rp_ratscity/doppeltuer2.mdl"] = true
}

local LocalPlayer = LocalPlayer
local Vector = Vector
local Angle = Angle
local cam = cam
local cam_Start3D = cam.Start3D
local cam_End3D = cam.End3D
local cam_Start3D2D = cam.Start3D2D
local cam_End3D2D = cam.End3D2D
local draw = draw
local draw_SimpleTextOutlined = draw.SimpleTextOutlined
local surface = surface
local surface_SetFont = surface.SetFont
local surface_GetTextSize = surface.GetTextSize

local use_font = system.IsWindows() and "Tahoma" or "Verdana"
surface.CreateFont("DoorDisplay_TitleFont", {font = use_font, size = 116, weight = 1000, antialias = true})
surface.CreateFont("DoorDisplay_TitleFont_Small", {font = use_font, size = 72, weight = 1000, antialias = true})
surface.CreateFont("DoorDisplay_SmallFont", {font = use_font, size = 48, weight = 1000, antialias = true})
surface.CreateFont("DoorDisplay_GroupFont", {font = use_font, size = 72, weight = 1000, antialias = true})

local function ColorMultiplyAlpha(col, mul)
	return Color(col.r, col.g, col.b, col.a * mul)
end

local function GetCoOwners(door, doordata)
	local coowners = {}
	local tsize = 0
	for uid in pairs(door.extraOwners or {}) do
		local ply = Player(uid)
		if !IsValid(ply) then continue end
		tsize = tsize + 1
		table.insert(coowners, ply)
	end
	return coowners, tsize
end

local function GetAllowedCoOwners(door, doordata)
	local a_coowners = {}
	local tsize = 0
	for uid in pairs(door.allowedToOwn or {}) do
		local ply = Player(uid)
		if !IsValid(ply) then continue end
		tsize = tsize + 1
		table.insert(a_coowners, ply)
	end
	return a_coowners, tsize
end

local function GetAllowedTeamNames(door, doordata)
	local names = {}
	local doorgroup = doordata.groupOwn
	local tsize = 0
	if doorgroup then
		tsize = 1
		table.insert(names, doorgroup)
	else
		for tid in pairs(doordata.teamOwn or {}) do
			local tname = team.GetName(tid)
			if tname then
				tsize = tsize + 1
				table.insert(names, tname)
			end
		end
	end
	return names, tsize
end

local reg = debug.getregistry()

local GetPos = reg.Entity.GetPos
local EyePos = reg.Entity.EyePos
local IsValid_ent = reg.Entity.IsValid
local IsDormant = reg.Entity.IsDormant
local GetNoDraw = reg.Entity.GetNoDraw
local DistToSqr = reg.Vector.DistToSqr

local local_ply, eye_pos, trace_ent, sqr_dist, dinfo, campos, camang, lpos, lang, ang, dot, admul, drawpos, doordata, title, title_font, title_width, title_length, owner, allowedgroups, groupcount
local door_info = {}
local max_distance = DrawDistance * DrawDistance
local angle_zero = Angle(0, 0, 0)
local angle_back = Angle(0, 180, 0)
local function DrawDoorDisplay(door, eye_pos)
	if IsDormant(door) or GetNoDraw(door) then return end
	sqr_dist = DistToSqr(eye_pos, GetPos(door))
	if sqr_dist < max_distance then
		doordata = door:getDoorData()
		if !doordata then return end
		dinfo = door_info[door]
		if !dinfo then
			door_info[door] = {}
			local maxs = door:OBBMaxs()
			local mins = door:OBBMins()
			local center = door:OBBCenter()
			local size = mins - maxs
			size = Vector(math.abs(size.x), math.abs(size.y), math.abs(size.z))
			local worldcenter = door:LocalToWorld(center)
			local trace_tbl = {
				endpos = worldcenter
			}
			local offset
			local drawang
			local canvaspos1
			local canvaspos2
			if size.x > size.y then
				drawang = Angle(0, 0, 90)
				trace_tbl.start = worldcenter + door:GetRight() * (size.y / 2)
				local thickness = util.TraceLine(trace_tbl).Fraction * (size.y / 2) + 0.1
				offset = Vector(size.x / 2,thickness,0)
			else
				drawang = Angle(0, 90, 90)
				trace_tbl.start = worldcenter + door:GetForward() * (size.x / 2)
				local thickness = (1 - util.TraceLine(trace_tbl).Fraction) * (size.x / 2) + 0.1
				offset = Vector(-thickness, size.y / 2, 0)
			end
			local heightoffset = Vector(0, 0, 25)
			canvaspos1 = center - offset + heightoffset
			canvaspos2 = center + offset + heightoffset
			local scale = 0.05
			local canvaswidth
			if size.x > size.y then
				canvaswidth = size.x / scale
			else
				canvaswidth = size.y / scale
			end
			door_info[door] = {
				drawang = drawang,
				canvaspos1 = canvaspos1,
				canvaspos2 = canvaspos2,
				scale = scale,
				canvaswidth = canvaswidth,
				start = trace_tbl.start
			}
			dinfo = door_info[door]
		end
		campos, camang = dinfo.canvaspos1, angle_zero
		lpos, lang = Vector(), Angle()
		lpos:Set(dinfo.canvaspos1)
		lang:Set(dinfo.drawang)
		ang = door:LocalToWorldAngles(lang)
		dot = ang:Up():Dot(eye_pos - door:WorldSpaceCenter())
		if dot < 0 then
			campos, camang = dinfo.canvaspos2, angle_back
		end
		admul = 1 - (sqr_dist / max_distance)
		title = doordata.title
		owner = doordata.owner and Player(doordata.owner)
		owner = IsValid(owner) and owner
		allowedgroups, groupcount = GetAllowedTeamNames(door, doordata)
		cam_Start3D()
			cam_Start3D2D(door:LocalToWorld(campos), dinfo.drawang + door:GetAngles() + camang, dinfo.scale)
				drawpos = dinfo.canvaswidth / 2
				if title then
					title_font = "DoorDisplay_TitleFont"
					surface_SetFont(title_font)
					title_width = surface_GetTextSize(title)
					if title_width > 450 then
						title_font = "DoorDisplay_TitleFont_Small"
					end
					title_length = #title
					if title_length > 20 then
						title = string.sub(title, 1, 20)..".."
					end
					if groupcount < 1 and owner then
						draw_SimpleTextOutlined(title, title_font, drawpos, 0, ColorMultiplyAlpha(PlayerTitleColor, admul), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, ColorMultiplyAlpha(PlayerTitleOutlineColor, admul))
					else
						draw_SimpleTextOutlined(title, title_font, drawpos, 0, ColorMultiplyAlpha(DoorTitleColor, admul), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, ColorMultiplyAlpha(DoorTitleOutlineColor, admul))
					end
				end
				if groupcount < 1 then
					if !owner and !door:getKeysNonOwnable() then
						draw_SimpleTextOutlined("Zu Verkaufen", "DoorDisplay_TitleFont", drawpos, 0, ColorMultiplyAlpha(SellTitleColor, admul), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, ColorMultiplyAlpha(SellTitleOutlineColor, admul))
					end
					if owner then
						draw_SimpleTextOutlined(owner:Name(), "DoorDisplay_TitleFont_Small", drawpos, 120, ColorMultiplyAlpha(OwnerColor, admul), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, ColorMultiplyAlpha(OwnerOutlineColor, admul))
						local coowners, c_count = GetCoOwners(door, doordata)
						if c_count > 0 then
							local names = {}
							for i=1, c_count do
								table.insert(names, coowners[i]:Name())
							end
							table.sort(names)
							local coowners_color = ColorMultiplyAlpha(CoOwnersColor, admul)
							local coowners_outline_color = ColorMultiplyAlpha(CoOwnersOutlineColor, admul)
							for i=1, #names do
								local name = names[i]
								local leng = #name
								if leng > 20 then
									title = string.sub(name, 1, 20)..".."
								end
								draw_SimpleTextOutlined(name, "DoorDisplay_SmallFont", drawpos, 160 + 50 * i, coowners_color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, coowners_outline_color)
							end
						end
						local a_coowners, a_count = GetAllowedCoOwners(door, doordata)
						if a_count > 0 then
							local names = {}
							for i=1, a_count do
								table.insert(names, a_coowners[i]:Name())
							end
							table.sort(names)
							local a_coowners_color = ColorMultiplyAlpha(AllowedCoOwnersColor, admul)
							local a_coowners_outline_color = ColorMultiplyAlpha(CoOwnersOutlineColor, admul)
							for i=1, #names do
								local name = names[i]
								local leng = #name
								if leng > 20 then
									title = string.sub(name, 1, 20)..".."
								end
								if c_count > 0 then
									draw_SimpleTextOutlined(name, "DoorDisplay_SmallFont", drawpos, 200 + 50 * c_count + 50 * i, a_coowners_color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, a_coowners_outline_color)
								else
									draw_SimpleTextOutlined(name, "DoorDisplay_SmallFont", drawpos, 200 + 50 * i, a_coowners_color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, a_coowners_outline_color)
								end
							end
						end
					end
				else
					local allowedgroups_color = ColorMultiplyAlpha(AllowedTeamsColor, admul)
					local allowedgroups_outline_color = ColorMultiplyAlpha(AllowedTeamsOutlineColor, admul)
					for i=1, groupcount do
						draw_SimpleTextOutlined(allowedgroups[i], "DoorDisplay_GroupFont", drawpos, 140 + 60 * (i - 1), allowedgroups_color, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 1, allowedgroups_outline_color)
					end
				end
			cam_End3D2D()
		cam_End3D()
	end
end

local showdoordisplay = CreateClientConVar("cl_showdoordisplay", 1, FCVAR_ARCHIVE)
local performance_mode = CreateClientConVar("cl_doordisplay_performance", 0, FCVAR_ARCHIVE)

local doors_to_render = {}
local function CheckForDoors()
	if !showdoordisplay:GetBool() or performance_mode:GetBool() then return end
	local ply = LocalPlayer()
	if !ply:IsValid() then return end
	doors_to_render = {}
	for _, v in ipairs(ents.FindInSphere(ply:EyePos(), DrawDistance + 100)) do
		if FunctioningDoors[v:GetClass()] and !DisabledDoors[v:GetModel()] then
			table.insert(doors_to_render, v)
		end
	end
end
timer.Create("DarkRP_CheckForDoors", 0.2, 0, CheckForDoors)

local local_ply
local function DrawOverlays()
	if !showdoordisplay:GetBool() then return end
	local_ply = local_ply or LocalPlayer()
	if !performance_mode:GetBool() then
		eye_pos = EyePos(local_ply)
		for _, door in ipairs(doors_to_render) do
			if !IsValid_ent(door) then continue end
			DrawDoorDisplay(door, eye_pos)
		end
	else
		trace_ent = local_ply:GetEyeTrace().Entity
		if IsValid(trace_ent) then
			class = trace_ent:GetClass()
			if FunctioningDoors[class] and !DisabledDoors[class] then
				eye_pos = EyePos(local_ply)
				DrawDoorDisplay(trace_ent, eye_pos)
			end
		end
	end
end
hook.Add("RenderScreenspaceEffects", "door_display_drawoverlay", DrawOverlays)