-- LUALOCALS < ---------------------------------------------------------
local S, addgroups, get_mod_api, minetest, pairs, string, type, vector
    = S, addgroups, get_mod_api, minetest, pairs, string, type, vector
local string_gmatch, string_lower, string_match, string_sub,
      string_upper
    = string.gmatch, string.lower, string.match, string.sub,
      string.upper
-- LUALOCALS > ---------------------------------------------------------

local api = get_mod_api()

local colors = {
	red = true,
	green = true,
	blue = true,
	cyan = true,
	yellow = true,
	magenta = true,
	orange = true,
	black = true,
	white = true,
	purple = true,
	violet = "Purple",
	pink = true,
	gold = true,
	russet = true,
	brown = true,
	cloudy = true,
}
for k, v in pairs(colors) do
	if type(v) ~= "string" then
		v = (string_upper(string_sub(k, 1, 1))
			.. string_sub(k, 2))
	end
	colors[k] = S(v)
end

local grouppref = "color_hud_"
addgroups("piredo_terrain:piranesi__black", grouppref .. "none")
local function get_item_color_raw(name)
	local def = minetest.registered_items[name]
	if not def then return end

	local groups = def.groups or {}
	if groups.collectable and groups.collectable > 0 then
		return def.description
	end

	do
		local none = groups[grouppref .. "none"]
		if none and none > 0 then return end
	end
	for k, v in pairs(colors) do
		local cg = groups[grouppref .. k]
		if cg and cg > 0 then
			return v
		end
	end

	local descname = string_lower((def.description or "") .. " " .. name)

	if not string_match(descname, "wool_") then return end

	for s in string_gmatch(descname, "%w+") do
		if colors[s] then return colors[s] end
	end
end

local get_item_color
do
	local cache = {}
	get_item_color = function(name)
		local found = cache[name]
		if found then return found[1] end
		found = {get_item_color_raw(name)}
		cache[name] = found
		return found[1]
	end
end

local function get_pointed_color(player)
	local start = player:get_pos()
	start.y = start.y + player:get_properties().eye_height
	local target = vector.add(start, vector.multiply(player:get_look_dir(), 50))
	for pt in minetest.raycast(start, target, false, false) do
		if pt.type == "node" then
			local meta = minetest.get_meta(pt.under)
			local desc = meta:get_string("description")
			if desc and desc ~= "" then return desc, pt.under end
			return get_item_color(minetest.get_node(pt.under).name), pt.under
		end
	end
end

local now = 0
minetest.register_globalstep(function(dtime) now = now + dtime end)

local pointdata = api.create_player_data()
api.register_playerstep(function(player, _, pname)
		local data = pointdata(pname)

		local text, pos = get_pointed_color(player)
		text = text or ""
		pos = pos or vector.round(player:get_pos())
		if not (data.oldpos and vector.equals(pos, data.oldpos)) then
			data.start = now + 0.4
			data.oldpos = pos
		end
		if now < data.start then text = "" end

		if not data.hud then
			data.hud = player:hud_add({
					hud_elem_type = "waypoint",
					world_pos = pos,
					number = 0xFFFFFF,
					precision = 0,
					name = text
				})
			data.hudtext = text
			data.hudpos = pos
		else
			if data.hudtext ~= text then
				player:hud_change(data.hud, "name", text)
				data.hudtext = text
			end
			if not vector.equals(pos, data.hudpos) then
				player:hud_change(data.hud, "world_pos", pos)
				data.hudpos = pos
			end
		end
	end)
