-- @module plugins.window_test2

-- 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.

--- Wide VirtualTree manual test window

local core = require("core")
local qui = require("qui")
local palette = require("qui.palette")
local theme = require("qui.theme")
local Button = require("qui.button")
local Label = require("qui.label")
local VirtualTree = require("qui.vtree")

local window_test2 = {}

local opened_forms = {}		-- Retains each Form until its native Window completes
local next_window_number = 1	-- Keeps repeated test Windows easy to identify

--- Create the wide generated-file VirtualTree and its focused diagnostics
-- @param title string native Window and Form title
-- @return table|nil form
-- @return string|nil error_text
local function create_test_form(title)
	local file_nodes = {}
	local frame_counts = {
		provider = 0,
		style = 0,
		background = 0,
		overlay = 0,
	}
	local result_counts = {
		provider = 0,
		style = 0,
		background = 0,
		overlay = 0,
	}
	local latest_counts = {
		provider = 0,
		style = 0,
		background = 0,
		overlay = 0,
	}
	local result_name = "Initial draw"
	local pending_result = "Initial draw"
	local provider_descending = false	-- Lets header sorting visibly reverse the generated provider order

	--- Return one stable generated file row without building rows that were never requested
	-- @param _ table|nil unused parent for the flat tree
	-- @param index number one-based root index
	-- @return table node
	local function file_node(_, position)
		local index = provider_descending and 100001 - position or position
		local node = file_nodes[index]
		if not node then
			node = {
				index = index,
				file_name = string.format("%05d - Generated audio file.flac", index),
				parent = index % 2 == 0 and "Library\\Albums" or "Library\\Incoming",
				size = string.format("%.2f MB", 2.5 + index % 37 * 0.73),
				duration = string.format("%d:%02d", 1 + index % 8, index * 7 % 60),
				modified = string.format(
					"2026-07-%02d  %02d:%02d",
					1 + index % 28,
					index % 24,
					index * 3 % 60
				),
			}
			file_nodes[index] = node
		end

		return node
	end

	local file_vtree = VirtualTree {
		name = "file_vtree",
		root_count = function()
			return 100000
		end,
		child_count = function()
			return 0
		end,
		child = file_node,
		has_children = function()
			return false
		end,
		columns = {
			{ name = "order", caption = "Order", width = 72, align = "right" },
			{ name = "file_name", caption = "File Name", width = 720, min_width = 180 },
			{ name = "parent", caption = "Parent", width = 440, min_width = 140 },
			{ name = "size", caption = "Size", width = 130, align = "right" },
			{ name = "duration", caption = "Duration", width = 110, align = "right" },
			{
				name = "modified",
				caption = "Modified",
				width = 300,
				min_width = 180,
				sortable = false,
			},
		},
		main_column = "file_name",
		sort_column = "file_name",
		sort_direction = "ascending",
		on_column_resize = function(_, column, width)
			pending_result = string.format("Resized %s to %d DIP", column.name, width)
		end,
		on_sort = function(_, column, direction)
			provider_descending = direction == "descending"
			pending_result = string.format("Sorted %s %s", column.name, direction)
		end,
		cell_text = function(node, column)
			frame_counts.provider = frame_counts.provider + 1
			if column.name == "order" then
				return tostring(node.index)
			end

			return node[column.name]
		end,
		-- These two small variations prove that ordinary QUI drawing remains available
		cell_style = function(_, cell, style)
			frame_counts.style = frame_counts.style + 1
			if cell.column.name ~= "file_name" then
				return
			end
			if cell.node.index % 25 == 0 then
				style.background = palette.blue.soft.color
			end
			if cell.node.index % 20 == 0 then
				style.text_color = palette.orange.strong.color
			end
		end,
		draw_cell_background = function()
			-- Count this empty layer so the real callback cost remains visible
			frame_counts.background = frame_counts.background + 1
		end,
		-- File-name overlays demonstrate cell decoration without replacing QUI text
		draw_cell_overlay = function(_, control_canvas, cell)
			frame_counts.overlay = frame_counts.overlay + 1
			if cell.column.name ~= "file_name" then
				return
			end

			local cell_line_color = theme.resolve(palette.blue.strong.color)
			local row_frame_color = theme.resolve(palette.red.strong.color)
			local maximum_width = math.max(1, cell.rect.width)
			local line_width = ((cell.node.index * 2 - 1) % maximum_width) + 1
			control_canvas:draw_horizontal_line(
				cell.rect.x,
				cell.rect.y + cell.rect.height - 1,
				line_width,
				1,
				cell_line_color
			)

			-- One known column draws both edges so the row frame is not repeated per cell
			if cell.node.index % 50 == 0 then
				control_canvas:draw_horizontal_line(
					cell.row_rect.x,
					cell.row_rect.y,
					cell.row_rect.width,
					1,
					row_frame_color
				)
				control_canvas:draw_horizontal_line(
					cell.row_rect.x,
					cell.row_rect.y + cell.row_rect.height - 1,
					cell.row_rect.width,
					1,
					row_frame_color
				)
			end
		end,
		placement = {
			horizontal = "stretch",
			vertical = "stretch",
		},
	}
	local draw_file_vtree = file_vtree.draw

	--- Count one complete VirtualTree frame and retain a requested demonstration result
	-- Continuous Window drawing must not bury a focused refresh beneath later frames
	function file_vtree:draw(control_canvas)
		frame_counts.provider = 0
		frame_counts.style = 0
		frame_counts.background = 0
		frame_counts.overlay = 0

		draw_file_vtree(self, control_canvas)

		latest_counts.provider = frame_counts.provider
		latest_counts.style = frame_counts.style
		latest_counts.background = frame_counts.background
		latest_counts.overlay = frame_counts.overlay

		if pending_result then
			result_name = pending_result
			result_counts.provider = frame_counts.provider
			result_counts.style = frame_counts.style
			result_counts.background = frame_counts.background
			result_counts.overlay = frame_counts.overlay
			pending_result = nil
		end
	end

	local column_status = Label {
		name = "file_vtree_column_status",
		text = "Columns waiting for first layout",
		placement = {
			horizontal = "stretch",
			vertical = "center",
		},
	}
	local draw_column_status = column_status.draw

	--- Show the resolved main-column result from the frame that was just drawn
	-- Reading retained geometry here never asks the virtual provider for another cell
	function column_status:draw(control_canvas)
		local main_width = 0
		for _, column in ipairs(file_vtree.columns) do
			if column.name == file_vtree.main_column then
				main_width = column.resolved_width or 0
				break
			end
		end
		self.text = string.format(
			"Viewport: %d DIP | Content: %d DIP | Main: %s %d DIP | Fit: %s | Sort: %s %s",
			file_vtree._column_geometry_available or 0,
			file_vtree._column_content_width or 0,
			file_vtree.main_column,
			main_width,
			file_vtree.fit_to_width and "on" or "off",
			file_vtree.sort_column,
			file_vtree.sort_direction
		)
		draw_column_status(self, control_canvas)
	end

	local latest_status = Label {
		name = "file_vtree_latest_counters",
		text = "Latest frame - Provider: 0 | Style: 0 | Background: 0 | Overlay: 0",
		placement = {
			horizontal = "stretch",
			vertical = "center",
		},
	}
	local draw_latest_status = latest_status.draw

	--- Draw the latest counters without asking the Window for another frame
	function latest_status:draw(control_canvas)
		self.text = string.format(
			"Latest frame - Provider: %d | Style: %d | Background: %d | Overlay: %d",
			latest_counts.provider,
			latest_counts.style,
			latest_counts.background,
			latest_counts.overlay
		)
		draw_latest_status(self, control_canvas)
	end

	local result_status = Label {
		name = "file_vtree_counters",
		text = "Last requested: Initial draw - Provider: 0 | Style: 0 | Background: 0 | Overlay: 0",
		placement = {
			horizontal = "stretch",
			vertical = "center",
		},
	}
	local draw_result_status = result_status.draw

	--- Draw the retained requested-result counters without scheduling another frame
	function result_status:draw(control_canvas)
		self.text = string.format(
			"Last requested: %s - Provider: %d | Style: %d | Background: %d | Overlay: %d",
			result_name,
			result_counts.provider,
			result_counts.style,
			result_counts.background,
			result_counts.overlay
		)
		draw_result_status(self, control_canvas)
	end

	--- Return the selected file or the first currently displayed flat root
	-- @return table node stable generated file row
	local function current_file_node()
		return file_vtree.selected_node or file_node(nil, file_vtree.first_visible)
	end

	--- Report one failed VirtualTree demonstration update without hiding the test Window
	-- @param changed boolean|nil successful update result
	-- @param error_text string|nil update error
	local function report_update(changed, error_text)
		if not changed then
			pending_result = nil
			core.error("Wide VirtualTree update failed: %s", tostring(error_text))
		end
	end

	local change_cell_button = Button {
		name = "change_file_vtree_cell",
		caption = "Change one cell",
		on_click = function()
			local node = current_file_node()
			pending_result = "Changed one cell"
			node.cell_revision = (node.cell_revision or 0) + 1
			node.file_name = string.format(
				"%05d - Generated audio file r%d.flac",
				node.index,
				node.cell_revision
			)
			report_update(file_vtree:invalidate_cell(node, "file_name"))

			return true
		end,
	}
	local change_row_button = Button {
		name = "change_file_vtree_row",
		caption = "Change one row",
		on_click = function()
			local node = current_file_node()
			pending_result = "Changed one row"
			node.row_revision = (node.row_revision or 0) + 1
			node.parent = "Library\\Updated " .. tostring(node.row_revision)
			node.size = string.format("%.2f MB", 10 + node.row_revision * 0.5)
			report_update(file_vtree:invalidate_node(node))

			return true
		end,
	}
	local refresh_visible_button = Button {
		name = "refresh_file_vtree_visible",
		caption = "Refresh visible cells",
		on_click = function()
			pending_result = "Refreshed visible cells"
			report_update(file_vtree:invalidate_visible())

			return true
		end,
	}
	local reset_counters_button = Button {
		name = "reset_file_vtree_counters",
		caption = "Reset counters",
		on_click = function()
			result_name = "No refresh measured"
			result_counts.provider = 0
			result_counts.style = 0
			result_counts.background = 0
			result_counts.overlay = 0
			pending_result = nil

			return true
		end,
	}

	-- The wide tree owns almost the entire Window; only its diagnostics sit below it
	return qui.form {
		name = title,
		layout = qui.rows {
			gap = 6,
			padding_left = 12,
			padding_top = 12,
			padding_right = 12,
			padding_bottom = 12,

			qui.pane {
				name = "wide_virtual_tree_surface",
				length = "weighted",
				weight = 1,
				controls = { file_vtree },
			},

			qui.pane {
				name = "wide_virtual_tree_column_status",
				length = "content",
				controls = { column_status },
			},

			qui.pane {
				name = "wide_virtual_tree_latest_status",
				length = "content",
				controls = { latest_status },
			},

			qui.pane {
				name = "wide_virtual_tree_result_status",
				length = "content",
				controls = { result_status },
			},

			qui.pane {
				name = "wide_virtual_tree_actions",
				length = "content",
				layout = qui.cols {
					name = "wide_virtual_tree_action_columns",
					gap = 8,

					qui.pane {
						name = "wide_virtual_tree_action_filler",
						length = "weighted",
						weight = 1,
					},

					qui.pane {
						name = "change_file_vtree_cell_action",
						length = "content",
						controls = { change_cell_button },
					},

					qui.pane {
						name = "change_file_vtree_row_action",
						length = "content",
						controls = { change_row_button },
					},

					qui.pane {
						name = "refresh_file_vtree_visible_action",
						length = "content",
						controls = { refresh_visible_button },
					},

					qui.pane {
						name = "reset_file_vtree_counters_action",
						length = "content",
						controls = { reset_counters_button },
					},
				},
			},
		},
	}
end

--- Open one independent wide VirtualTree utility Window
function window_test2.open()
	local title = string.format("Lx Wide VirtualTree Test %d", next_window_number)
	local built_form, build_error = create_test_form(title)

	if not built_form then
		core.error("Wide VirtualTree test Form failed: %s", tostring(build_error))
		return false
	end

	local window_id
	built_form.on_complete = function(_, result)
		if window_id then
			opened_forms[window_id] = nil
			core.log("Closed wide VirtualTree test window %d with result '%s'", window_id, tostring(result))
		else
			core.log("Wide VirtualTree Form completed while Window opening was rolled back")
		end
	end

	local open_error
	window_id, open_error = built_form:open_window {
		title = title,
		width = 1500,
		height = 900,
		resizable = true,
	}

	if not window_id then
		if built_form:is_valid() then
			built_form:destroy()
		end
		core.error("Wide VirtualTree test open failed: %s", tostring(open_error))
		return false
	end

	next_window_number = next_window_number + 1
	opened_forms[window_id] = built_form
	core.log("Opened wide VirtualTree test window %d", window_id)

	return true
end

return window_test2
