-- lx-bundle:true

--- Strip raw RTF editor content into plain text or Markdown
-- Mirrors the TSV align workflow for in-place and new-tab processing
-- @module plugins.rtfutils

local core = require("core")
local command = require("core.command")
local Doc = require("core.doc")
local formatter = require("plugins.rtfutils.formatter")

local function active_rtf_doc()
	local view = core.active_view
	local doc = view and view.doc
	local filename = doc and doc.filename

	if not doc or doc.is_binary_placeholder == true then
		return nil
	end

	if type(filename) == "string" and filename:lower():match("%.rtf$") then
		return doc
	end

	return nil
end

local function is_active_rtf()
	return active_rtf_doc() ~= nil
end

--- Keep selected trailing empty lines aligned with other line-oriented commands
-- @param doc Doc active document
-- @return integer line1 start line
-- @return integer line2 end line
-- @return boolean has_selection true when a selection exists
local function get_target_line_range(doc)
	if doc:has_selection() then
		local line1, _, line2, col2 = doc:get_selection(true)
		if line2 > line1 and col2 == 1 then
			line2 = line2 - 1
		end

		if line2 < line1 then
			line2 = line1
		end

		return line1, line2, true
	end

	return 1, #doc.lines, false
end

--- Read the selected text block or the whole document text
-- @param doc Doc active document
-- @return string text to transform
local function get_target_text(doc)
	local line1, line2, has_selection = get_target_line_range(doc)
	if has_selection then
		return doc:get_text(line1, 1, line2, math.huge)
	end

	return doc:get_text(1, 1, #doc.lines, #doc.lines[#doc.lines])
end

--- Open a new text document and fill it with transformed output
-- @param source_doc Doc active source document
-- @param content string transformed text
-- @param output_suffix string new filename suffix
local function open_output_doc(source_doc, content, output_suffix)
	local doc = Doc.create((source_doc.filename or "untitled") .. output_suffix)
	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

--- Replace either the selected lines or the full document with stripped text
-- @param doc Doc active document
local function strip_inline(doc)
	local line1, line2, has_selection = get_target_line_range(doc)
	if has_selection then
		doc:replace_range(line1, 1, line2, math.huge, function(text)
			return formatter.to_plain_text(text)
		end)
		return
	end

	doc:replace(function(text)
		return formatter.to_plain_text(text)
	end)
end

command.add({
	["rtf:strip"] = {
		requires = { "doc", "edit" },
		predicate = is_active_rtf,
		perform = function()
			local doc = active_rtf_doc()
			open_output_doc(doc, formatter.to_plain_text(get_target_text(doc)), ".txt")
		end,
	},
	["rtf:strip-inplace"] = {
		requires = { "doc", "edit" },
		predicate = is_active_rtf,
		perform = function()
			strip_inline(active_rtf_doc())
		end,
	},
	["rtf:strip-to-markdown"] = {
		requires = { "doc" },
		predicate = is_active_rtf,
		perform = function()
			local doc = active_rtf_doc()
			open_output_doc(doc, formatter.to_markdown_text(get_target_text(doc)), ".md")
		end,
	},
})
