---@diagnostic disable: duplicate-set-field,param-type-mismatch
-- lx-bundle:true

local common = require("core.common")
local config = require("core.config")
local DocView = require("core.text.editor")
local style = require("core.style")

local white = common.color("#ffffff")
local black = common.color("#000000")
local tmp = {}

-- Choose readable text color for an RGB background (luminance based)
local function text_color_for_rgb(r, g, b)
	local luma = 0.2126 * r + 0.7152 * g + 0.0722 * b
	return (luma < 140) and white or black
end
-- Draw mode for color previews: "bg" or "alt"
local draw_mode = "alt"

local function draw_color_previews(self, idx, x, y, ptn, base, nibbles, opts)
	opts = opts or {}
	local text = self.doc.lines[idx]
	local s, e = 0, 0

	while true do
		s, e = text:find(ptn, e + 1)
		if not s then
			break
		end

		-- Require non-word boundaries around color tokens (avoid #define)
		local prev_char = (s > 1) and text:sub(s - 1, s - 1) or ""
		local next_char = text:sub(e + 1, e + 1)
		local prev_ok = (prev_char == "") or not prev_char:match("[%w_]")
		if opts.skip_entity_prefix and prev_char == "&" then
			prev_ok = false
		end
		if opts.skip_bracket_prefix and prev_char == "[" then
			prev_ok = false
		end
		local next_ok = (next_char == "") or not next_char:match("[%w_]")
		local in_url_fragment = false
		if opts.skip_url_fragments and prev_ok and next_ok then
			local tok_start = s - 1
			while tok_start >= 1 and not text:sub(tok_start, tok_start):match("%s") do
				tok_start = tok_start - 1
			end
			local token_prefix = text:sub(tok_start + 1, s - 1)
			in_url_fragment = token_prefix:find("://", 1, true) ~= nil
		end
		if prev_ok and next_ok and not in_url_fragment then
			local str = text:sub(s, e)
			local r, g, b = str:match(ptn)
			r, g, b = tonumber(r, base), tonumber(g, base), tonumber(b, base)

			-- #123 becomes #112233
			if nibbles then
				r = r * 16
				g = g * 16
				b = b * 16
			end

			local x1 = x + self:get_col_x_offset(idx, s)
			local x2 = x + self:get_col_x_offset(idx, e + 1)
			local oy = self:get_line_text_y_offset()

			local text_color = text_color_for_rgb(r, g, b)
			tmp[1], tmp[2], tmp[3] = r, g, b

			local l1, _, l2, _ = self.doc:get_selection(true)

			if not (self.doc:has_selection() and idx >= l1 and idx <= l2) then
				if draw_mode == "alt" then
					-- Alt mode fills background, 1px border, inverted text color
					local h = self:get_line_height()
					renderer.draw_rect(x1, y, x2 - x1, h, tmp)
					local border = 1 * SCALE
					renderer.draw_rect(x1, y, x2 - x1, border, tmp)
					renderer.draw_rect(x1, y + h - border, x2 - x1, border, tmp)
					renderer.draw_rect(x1, y, border, h, tmp)
					renderer.draw_rect(x2 - border, y, border, h, tmp)
					renderer.draw_text(self:get_font(), str, x1, y + oy, text_color_for_rgb(r, g, b))
				else
					renderer.draw_rect(x1, y, x2 - x1, self:get_line_height(), tmp)
					renderer.draw_text(self:get_font(), str, x1, y + oy, text_color)
				end
			end
		end
	end
end

local draw_line_text = DocView.draw_line_text

function DocView:draw_line_text(idx, x, y)
	draw_line_text(self, idx, x, y)
	-- Skip expensive color token scans on very long lines
	if #(self.doc.lines[idx] or "") > (config.long_line_threshold or 5000) then
		return
	end
	draw_color_previews(
		self, idx, x, y, "#(%x%x)(%x%x)(%x%x)%f[%X]", 16, nil,
		{ skip_entity_prefix = true, skip_bracket_prefix = true, skip_url_fragments = true }
	)
	draw_color_previews(
		self, idx, x, y, "#(%x)(%x)(%x)%f[%X]", 16, true,
		{ skip_entity_prefix = true, skip_bracket_prefix = true, skip_url_fragments = true }
	)
	-- support #rgb css format
	draw_color_previews(
		self, idx, x, y, "#(%x%x)(%x%x)(%x%x)%x%x%f[%X]", 16, nil,
		{ skip_entity_prefix = true, skip_bracket_prefix = true, skip_url_fragments = true }
	)
	-- support #rrggbbaa css format
	draw_color_previews(self, idx, x, y, "rgba?%((%d+)%D+(%d+)%D+(%d+).-%)", 10)
end
