---@diagnostic disable: duplicate-set-field
-- lx-bundle:true

local core = require("core")
local command = require("core.command")
local config = require("core.config")
local DocView = require("core.text.editor")
local TextDocument = require("core.text.document")

local cache = setmetatable({}, { __mode = "k" })

local function detect_indent(doc)
	for _, text in ipairs(doc.lines) do
		local str = text:match("^  +")
		if str then
			return "soft", #str
		end
		local str = text:match("^\t+")
		if str then
			return "hard"
		end
	end
end

local function update_cache(doc)
	local type, size = detect_indent(doc)
	if type then
		cache[doc] = { type = type, size = size }
	end
end

local new = TextDocument.new
function TextDocument:new(...)
	new(self, ...)
	update_cache(self)
end

local clean = TextDocument.clean
function TextDocument:clean(...)
	clean(self, ...)
	update_cache(self)
end

--- Run a function with one document's detected indentation settings
-- @param doc table|nil text document
-- @param fn function wrapped function
-- @return any ... wrapped return values
local function with_indent_override(doc, fn, ...)
	local c = cache[doc]

	if not c then
		return fn(...)
	end

	local type, size = config.tab_type, config.indent_size
	config.tab_type, config.indent_size = c.type, c.size or config.indent_size
	local results = table.pack(pcall(fn, ...))
	config.tab_type, config.indent_size = type, size

	if not results[1] then
		error(results[2], 0)
	end

	return table.unpack(results, 2, results.n)
end

local perform = command.perform
function command.perform(...)
	local active_view = core.active_view

	return with_indent_override(active_view and active_view.doc, perform, ...)
end

local draw = DocView.draw
function DocView:draw(...)
	return with_indent_override(self.doc, draw, self, ...)
end
