-- lx-bundle:true

local config = require("core.config")
local common = require("core.common")
local fonts = require("core.style.fonts")
local colors = require("core.style.colors")
local metrics = require("core.style.metrics")

local style = {}

-- Create a copy of a color with adjusted alpha (0..1 or 0..255)
function style.transparent(color, alpha)
	if
		type(color) ~= "table"
		or type(color[1]) ~= "number"
		or type(color[2]) ~= "number"
		or type(color[3]) ~= "number"
	then
		return color
	end
	local a = alpha
	if a <= 1 then
		a = a * 0xff
	end
	a = common.clamp(math.floor(a + 0.5), 0, 0xff)
	return { color[1], color[2], color[3], a }
end

-- Return a lightened copy of a color; clamp output channels only
function style.lighten(color, factor)
	if
		type(color) ~= "table"
		or type(color[1]) ~= "number"
		or type(color[2]) ~= "number"
		or type(color[3]) ~= "number"
	then
		return color
	end
	local f = factor or 0
	local r = common.clamp(math.floor(color[1] + (0xff - color[1]) * f + 0.5), 0, 0xff)
	local g = common.clamp(math.floor(color[2] + (0xff - color[2]) * f + 0.5), 0, 0xff)
	local b = common.clamp(math.floor(color[3] + (0xff - color[3]) * f + 0.5), 0, 0xff)
	return { r, g, b, color[4] }
end

-- Return a darkened copy of a color; clamp output channels only
function style.darken(color, factor)
	if
		type(color) ~= "table"
		or type(color[1]) ~= "number"
		or type(color[2]) ~= "number"
		or type(color[3]) ~= "number"
	then
		return color
	end
	local f = factor or 0
	local r = common.clamp(math.floor(color[1] * (1 - f) + 0.5), 0, 0xff)
	local g = common.clamp(math.floor(color[2] * (1 - f) + 0.5), 0, 0xff)
	local b = common.clamp(math.floor(color[3] * (1 - f) + 0.5), 0, 0xff)
	return { r, g, b, color[4] }
end

-- Heading level defaults used by outliner and syntax-level heading fallback
style.heading_level_max = style.heading_level_max or 6

-- Returns plain RGB(A) color from either a color table or a '{ fg, bg }' style entry
function style.as_plain_color(color)
	local c = color
	if type(c) == "table" and (c.fg or c.bg) then
		c = c.fg
	end
	if type(c) ~= "table" or type(c[1]) ~= "number" or type(c[2]) ~= "number" or type(c[3]) ~= "number" then
		return nil
	end
	return c
end

-- Returns a copy of 'color' with explicit alpha (0..255), accepting '{ fg, bg }'
function style.set_alpha(color, alpha)
	local plain = style.as_plain_color(color)
	if not plain then
		return color
	end
	return style.transparent(plain, alpha)
end

-- Resolve heading color for semantic level using explicit fallback chain
-- level<=0 or unset -> 'syntax.heading'
-- Missing headingN -> previous defined heading(N-1..1) -> 'syntax.heading'
function style.resolve_heading(level)
	local syntax = style.syntax or {}
	local base = syntax["heading"] or style.text
	local max_level = math.max(1, math.floor(tonumber(style.heading_level_max) or 6))
	local n = tonumber(level)
	if not n or n <= 0 then
		return base
	end
	n = math.floor(n)
	if n > max_level then
		n = max_level
	end
	for i = n, 1, -1 do
		local explicit = style["heading" .. i] or syntax["heading" .. i]
		if explicit then
			return explicit
		end
	end
	return base
end

-- Returns loaded style module names that map to existing data/styles/*.lua files
function style.get_loaded_style_modules()
	local items = {}

	for name in pairs(package.loaded) do

		if type(name) == "string" and (name:match("^styles%.") or name:match("^themes%.")) then
			local rel = name:gsub("%.", "/") .. ".lua"
			local path = DATA_DIR .. rel

			if system.is_file(path) == true then
				items[#items + 1] = name
			end
		end
	end

	table.sort(items)
	return items
end

-- Returns the current style module name when it can be resolved unambiguously
function style.get_active_style_module()
	local configured = config.current_style_module
	if type(configured) == "string" and configured ~= "" and package.loaded[configured] ~= nil then
		return configured
	end
	local loaded = style.get_loaded_style_modules()
	if #loaded == 1 then
		return loaded[1]
	end
	return nil
end

fonts.apply(style)
colors.apply(style)
metrics.apply(style)

return style
