-- lx-bundle:true

local navigate = {}

--- Reveal a line and column at shared line-jump position
-- Startup calls wait for first layout so viewport height is valid
-- @param line number target line
-- @param col number target column
-- @param view table document view
-- @param instant boolean|nil true to skip animation
function navigate.reveal_line_col(line, col, view, instant)
	-- Keep vertical anchor and horizontal reveal in one shared path
	local function reveal()
		view:scroll_to_line(line, false, instant)
		view:scroll_to_make_visible(line, col)
	end

	if view.size and view.size.y <= 0 then
		local core = require("core")
		local workspace_view = core.workspace_view
		if workspace_view and type(workspace_view.defer_draw) == "function" then
			-- First draw follows layout and provides final viewport size
			workspace_view:defer_draw(function()
				reveal()
				core.redraw = true
			end)
			return
		end
	end

	reveal()
end

--- Jump to a 1-based line and column with bounds validation
-- @param line number target line
-- @param col number|nil target column
-- @param view table|nil document view
-- @param instant boolean|nil true to skip animation
-- @return boolean ok
-- @return string|nil err
function navigate.jump_to_line_col(line, col, view, instant)
	view = view or require("core").active_view
	if not (view and view.doc) then
		return false, "No active document view"
	end

	local doc = view.doc
	if type(line) ~= "number" then
		return false, "Invalid line number"
	end
	line = math.floor(line)
	if line < 1 or line > #doc.lines then
		return false, string.format("Line out of range: %d (1-%d)", line, #doc.lines)
	end

	if col == nil then
		col = 1
	end
	if type(col) ~= "number" then
		return false, "Invalid column number"
	end
	col = math.floor(col)

	local maxcol = #doc.lines[line]
	if line == #doc.lines and doc.lines[line]:sub(-1) ~= "\n" then
		maxcol = maxcol + 1
	end
	if col < 1 or col > maxcol then
		return false, string.format("Column out of range on line %d: %d (1-%d)", line, col, maxcol)
	end

	doc:set_selection(line, col)
	navigate.reveal_line_col(line, col, view, instant)

	return true
end

--- Parse 'line' or 'line:column' input
-- @param text string user input
-- @return number|nil line
-- @return number|nil col
-- @return string|nil err
function navigate.parse_line_col(text)
	local trimmed = text:match("^%s*(.-)%s*$")
	if trimmed == "" then
		return nil, nil, "empty"
	end

	local line, col = trimmed:match("^(%d+)%s*:%s*(%d+)$")
	if line and col then
		return tonumber(line), tonumber(col)
	end

	line = trimmed:match("^(%d+)$")
	if line then
		return tonumber(line), nil
	end

	return nil, nil, "invalid"
end

return navigate
