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

-- Insert/Overwrite mode toggle for lite

local command = require("core.command")
local keymap = require("core.keymap")
local style = require("core.style")
local common = require("core.common")
local status_items = require("core.status.items")
local TextDocument = require("core.text.document")

local state = {
	overwrite = false,
}

local base_cursor_width = style.cursor_width
local base_cursor = { style.cursor[1], style.cursor[2], style.cursor[3], style.cursor[4] }
local overwrite_status_bg = {
	style.warning[1],
	style.warning[2],
	style.warning[3],
	48,
}

--- Apply the cursor shape that matches the current insert mode
-- @return nil
local function apply_cursor_style()
	if state.overwrite then
		style.cursor_width = math.max(base_cursor_width * 4, common.round(8 * SCALE))
		local alpha = math.max(96, math.floor((base_cursor[4] or 255) * 0.7))
		style.cursor = { base_cursor[1], base_cursor[2], base_cursor[3], alpha }
	else
		style.cursor_width = base_cursor_width
		style.cursor = { base_cursor[1], base_cursor[2], base_cursor[3], base_cursor[4] }
	end
end

local raw_text_input = TextDocument.text_input

--- Replace text under the caret while overwrite mode is active
-- @param text string input text
-- @return nil
function TextDocument:text_input(text)
	if state.overwrite and not self:has_selection() and not text:find("\n", 1, true) then
		local line, col = self:get_selection()
		local line_text = self.lines[line]
		local line_len = #line_text
		if line_text:sub(-1) == "\n" then
			line_len = line_len - 1
		end
		local available = math.max(0, line_len - col + 1)
		local remove_n = math.min(#text, available)
		if remove_n > 0 then
			self:remove(line, col, line, col + remove_n)
			self:set_selection(line, col)
		end
	end
	raw_text_input(self, text)
end

--- Return the shared status-item spec for overwrite mode
-- @return table status item spec
local function get_overwrite_item_spec()
	return {
		side = "right",
		order = 10000,
		priority = 1500,
		tooltip = "Overwrite mode is active  Press Insert to return to normal insert mode",

		predicate = function(context)
			return context.doc ~= nil and context.can_edit
		end,

		get_tokens = function()
			if state.overwrite then
				return { "Overwrite" }
			else
				return {}
			end
		end,

		get_color = function()
			if state.overwrite then
				return nil, overwrite_status_bg
			else
				return nil, nil
			end
		end,
	}
end

-- Register the overwrite state as a real status item so it can stay rightmost
local overwrite_item = status_items.get_item("insertmode_overwrite")
if not overwrite_item then
	local overwrite_item_spec = get_overwrite_item_spec()
	overwrite_item_spec.id = "insertmode_overwrite"
	overwrite_item = status_items.register(overwrite_item_spec)
else
	overwrite_item:update(get_overwrite_item_spec())
end

command.add({
	["insertmode:toggle"] = {
		requires = { "doc", "cursor" },
		perform = function()
			state.overwrite = not state.overwrite
			apply_cursor_style()
		end,
	},
})

keymap.add({
	["insert"] = "insertmode:toggle",
	["ins"] = "insertmode:toggle",
}, true)

apply_cursor_style()

return state
