-- lx-bundle:true

-- This file is part of Lx, created by Liqube <www.liqube.com>
-- Copyright Liqube Audio. All rights reserved.
-- Lx Interim License. See LICENSE for details.

--- Optional rendered Markdown preview registration
-- @module plugins.mdpreview

local command = require("core.command")
local common = require("core.common")
local config = require("core.config")
local core = require("core")
local keymap = require("core.keymap")
local open_handler = require("core.open_handler")

-- Export registers plugin-local page settings without loading preview view
local markdown_export = require("plugins.mdpreview.export")

config.plugins.mdpreview = common.merge({
	-- Automatically show or hide document outline when maximized or windowed
	auto_document_outline = false,
},
config.plugins.mdpreview)

--- Return whether commands currently target a rendered Markdown preview
-- @return boolean active true when focused view is this plugin's preview
local function is_active_markdown_preview()
	local active_view = core.active_view

	return active_view and active_view.is_markdown_preview == true or false
end

--- Create a Markdown preview while keeping its renderer unloaded until needed
-- @param request table shared open request
-- @return table view rendered Markdown view
local function create_preview(request)
	local MarkdownPreview = require("plugins.mdpreview.view")

	return MarkdownPreview(request.doc, request.options)
end

-- Format declares its preferred mode while this plugin supplies optional renderer
open_handler.register({
	name = "markdown",
	formats = { "md" },
	modes = { "preview" },
	create_view = create_preview,
})

-- Window mode changes redraw previews so automatic outline visibility takes effect immediately
if core.hook then
	core.hook.add("core.event", {
		id = "plugins.mdpreview.window_mode",
		windowmode = function()
			core.redraw = true
		end,
	})
end

command.register({
	-- Render complete document as numbered fixed-size PNG pages beside source file
	["md-preview:render-images"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			return markdown_export.start(core.active_view)
		end,
	},
	-- Outline clicks must be consumed before links or document panning
	["md-preview:open-outline"] = {
		predicate = is_active_markdown_preview,
		perform = function(context)
			if type(context) ~= "table" then
				return false
			end

			return core.active_view:open_outline_at(context.mouse_x, context.mouse_y)
		end,
	},
	-- Open links before same left press falls through to document panning
	["md-preview:open-link"] = {
		predicate = is_active_markdown_preview,
		perform = function(context)
			if type(context) ~= "table" then
				return false
			end

			return core.active_view:open_link_at(context.mouse_x, context.mouse_y)
		end,
	},
	-- Move one rendered body-row step while keeping shared scroll animation
	["md-preview:scroll-up"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_vertical_step(-1)
			return true
		end,
	},
	["md-preview:scroll-down"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_vertical_step(1)
			return true
		end,
	},
	-- Move by one visible page using same animation setting as TextViewer
	["md-preview:page-up"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_page(-1)
			return true
		end,
	},
	["md-preview:page-down"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_page(1)
			return true
		end,
	},
	-- Home and End are deliberate immediate jumps
	["md-preview:home"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_to_vertical_edge(false)
			return true
		end,
	},
	["md-preview:end"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:scroll_to_vertical_edge(true)
			return true
		end,
	},
	-- Backspace returns through positions saved immediately before heading jumps
	["md-preview:history-back"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			return core.active_view:scroll_to_previous_jump()
		end,
	},
	-- Adjacent heading commands share outline's active position and jump history
	["md-preview:previous-heading"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			return core.active_view:scroll_to_adjacent_heading(-1)
		end,
	},
	["md-preview:next-heading"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			return core.active_view:scroll_to_adjacent_heading(1)
		end,
	},
	-- Outline belongs to each preview tab and starts visible
	["md-preview:toggle-outline"] = {
		predicate = is_active_markdown_preview,
		perform = function()
			core.active_view:toggle_outline()
			return true
		end,
	},
})

-- Markdown previews offer direct zoom aliases and left-button panning
keymap.bind("plugin", {
	markdown_preview = {
		["lclick"] = {
			"md-preview:open-outline",
			"md-preview:open-link",
			"doc:mouse-pan",
		},
		["ctrl+d"] = "md-preview:toggle-outline",
		["up"] = "md-preview:scroll-up",
		["down"] = "md-preview:scroll-down",
		["alt+up"] = "md-preview:previous-heading",
		["alt+down"] = "md-preview:next-heading",
		["alt+wheelup"] = "md-preview:previous-heading",
		["alt+wheeldown"] = "md-preview:next-heading",
		-- Space follows usual document-reading page controls
		["shift+space"] = "md-preview:page-up",
		["space"] = "md-preview:page-down",
		["pageup"] = "md-preview:page-up",
		["pagedown"] = "md-preview:page-down",
		["ctrl+pageup"] = "md-preview:previous-heading",
		["ctrl+pagedown"] = "md-preview:next-heading",
		["home"] = "md-preview:home",
		["end"] = "md-preview:end",
		["ctrl+home"] = "md-preview:home",
		["ctrl+end"] = "md-preview:end",
		["backspace"] = "md-preview:history-back",
		["+"] = "zoom:in",
		["-"] = "zoom:out",
		["0"] = "zoom:reset",
		["keypad +"] = "zoom:in",
		["keypad -"] = "zoom:out",
		["keypad *"] = "zoom:reset",
		["ctrl+wheelup"] = "zoom:in",
		["ctrl+wheeldown"] = "zoom:out",
	},
})
