-- lx-bundle:true
---@diagnostic disable: duplicate-set-field,redundant-parameter
local fontcache = {}

local base_cache = setmetatable({}, { __mode = "v" })
local group_cache = setmetatable({}, { __mode = "v" })

-- Detect dead or transferred font handles so cache does not return unusable userdata
local function is_font_alive(font)
	if not font or type(font) ~= "userdata" then
		return false
	end
	local ok, h = pcall(font.get_height, font)
	return ok and type(h) == "number" and h > 0
end

-- Normalize key shape so repeated load requests hit the same cached font handle
local function make_base_key(filename, size)
	local n = tonumber(size) or 0
	return tostring(filename) .. "\31" .. string.format("%.4f", n)
end

-- Build stable key for grouped fallback fonts
local function make_group_key(primary_filename, size, fallback_paths)
	local n = tonumber(size) or 0
	local parts = {
		tostring(primary_filename),
		string.format("%.4f", n),
	}
	for _, path in ipairs(fallback_paths or {}) do
		parts[#parts + 1] = tostring(path)
	end
	return table.concat(parts, "\31")
end

-- Allow explicit cache reset for diagnostics or future runtime controls
function fontcache.clear()
	base_cache = {}
	group_cache = {}
end

-- Clear only grouped fallback cache entries
function fontcache.clear_groups()
	group_cache = {}
end

-- Clear only base renderer.font.load cache entries
function fontcache.clear_base()
	base_cache = {}
end

-- Load one font by path+size using shared cache
function fontcache.load(filename, size, ...)
	local key = make_base_key(filename, size)
	local hit = base_cache[key]
	if hit and is_font_alive(hit) then
		return hit
	end
	base_cache[key] = nil
	local font = renderer.font.load(filename, size, ...)
	base_cache[key] = font
	return font
end

-- Load primary+fallback font group through centralized grouped cache
function fontcache.load_group_with_fallbacks(primary_filename, size, fallback_paths, opts)
	opts = type(opts) == "table" and opts or {}
	local use_cache = opts.use_cache ~= false
	local paths = {}
	for _, path in ipairs(fallback_paths or {}) do
		paths[#paths + 1] = tostring(path)
	end

	local key = nil
	if use_cache then
		key = make_group_key(primary_filename, size, paths)
		local hit = group_cache[key]
		if hit and is_font_alive(hit) then
			return hit
		end
		group_cache[key] = nil
	end

	local primary = fontcache.load(primary_filename, size)
	if #paths == 0 then
		if key then
			group_cache[key] = primary
		end
		return primary
	end

	local group_font = nil
	group_font = renderer.font.group_lazy(primary, paths, size)

	if key then
		group_cache[key] = group_font
	end
	return group_font
end

-- Install one-time wrapper around renderer.font.load to dedupe Lua-side font loads
function fontcache.install()
	if renderer.font._lx_cached_load_installed then
		return true
	end

	local upstream = renderer.font.load

	renderer.font.load = function(filename, size, ...)
		local key = make_base_key(filename, size)
		local hit = base_cache[key]
		-- group_lazy transfers ownership out of primary handles and leaves stale userdata in cache
		if hit and is_font_alive(hit) then
			return hit
		end
		base_cache[key] = nil
		local font = upstream(filename, size, ...)
		base_cache[key] = font
		return font
	end

	renderer.font._lx_cached_load_installed = true
	return true
end

return fontcache
