---@diagnostic disable: need-check-nil
local core = require("core")
local command = require("core.command")
local Doc = require("core.doc")
local style = require("core.style")
local styledesc = require("core.format.styledesc")

local function sort_keys(map)
	local out = {}
	for k in pairs(map or {}) do
		out[#out + 1] = k
	end
	table.sort(out)
	return out
end

local function pad_right(text, width)
	local s = tostring(text or "")
	local missing = width - #s
	if missing > 0 then
		return s .. string.rep(" ", missing)
	end
	return s
end

local function split_lines(text)
	local s = tostring(text or "")
	if s == "" then
		return { "" }
	end
	local out = {}
	for line in (s .. "\n"):gmatch("(.-)\n") do
		out[#out + 1] = line
	end
	return out
end

local function append_aligned_table(lines, headers, rows)
	local min_widths = { 24, 56 }
	local widths = {}
	for i = 1, #headers do
		widths[i] = math.max(#(headers[i] or ""), min_widths[i] or 0)
	end

	for r = 1, #rows do
		local row = rows[r]
		for c = 1, #headers do
			local cell_lines = split_lines(row[c])
			for li = 1, #cell_lines do
				local cell = cell_lines[li]
				if #cell > widths[c] then
					widths[c] = #cell
				end
			end
		end
	end

	local function make_row(row, line_idx)
		line_idx = line_idx or 1
		local out = {}
		for i = 1, #headers do
			local cell_lines = split_lines(row[i])
			local cell = cell_lines[line_idx] or ""
			out[i] = " " .. pad_right(cell, widths[i]) .. " "
		end
		return "|" .. table.concat(out, "|") .. "|"
	end

	local divider = {}
	for i = 1, #headers do
		divider[i] = string.rep("-", widths[i] + 2)
	end

	lines[#lines + 1] = make_row(headers)
	lines[#lines + 1] = "|" .. table.concat(divider, "|") .. "|"
	for r = 1, #rows do
		local row = rows[r]
		local row_height = 1
		for c = 1, #headers do
			local h = #split_lines(row[c])
			if h > row_height then
				row_height = h
			end
		end
		for li = 1, row_height do
			lines[#lines + 1] = make_row(row, li)
		end
	end
end

local function build_rows()
	local rows = {}
	local seen = {}
	local entries = styledesc.get_entries() or {}
	for i = 1, #entries do
		local item = entries[i]
		local name = item and item.name
		local description = item and item.description
		if type(name) == "string" and name ~= "" then
			seen[name] = true
			rows[#rows + 1] = { name, description or "" }
		end
	end

	local extra = sort_keys(style.syntax)
	for i = 1, #extra do
		local name = extra[i]
		if not seen[name] then
			rows[#rows + 1] = { name, "No description available" }
		end
	end

	return rows
end

local function build_style_text()
	local rows = build_rows()
	local lines = {
		"Syntax Style Overview",
		"",
		string.format("Generated: %s", os.date("%Y-%m-%d %H:%M:%S")),
		"Source: runtime style.syntax and core.format.styledesc",
		"",
		string.format("Syntax Styles (%d)", #rows),
		"",
	}
	append_aligned_table(lines, { "Style", "Description" }, rows)
	lines[#lines + 1] = ""
	return table.concat(lines, "\n")
end

local function open_text_doc(content)
	local doc = Doc.create("syntax-styles.txt")
	core.workspace_view:open_doc(doc)
	local last_line = #doc.lines
	local last_col = #(doc.lines[last_line] or "") + 1
	doc:remove(1, 1, last_line, last_col)
	doc:insert(1, 1, content)
	doc:set_selection(1, 1)
end

command.register({
	["styletxt:generate"] = {
		perform = function()
			open_text_doc(build_style_text())
		end,
	},
})
