extends Node2D
## Bootstrap. Mounts the world view + UI overlay.
##
## Once we add menus / continue-game / new-game flows this will branch
## on game state. For Phase 1 it just instances the World and TopBar,
## which are children placed in main.tscn.
##
## Phase 15 — StorytellerBanner and StorytellerModal are runtime-instantiated
## here (same pattern as world.gd's BeautySystem / DirtinessSystem). Both are
## CanvasLayer nodes so they draw above the world regardless of scene-tree order.
##
## Phase 16 — LoadMenu (layer 25) and ResumeToast (layer 22) are runtime-
## instantiated here. LoadMenu ref is injected into TopBar so the Load button
## can call open() without a get_node("/root/…") call.

const STORYTELLER_BANNER_SCRIPT: Script    = preload("res://scenes/ui/storyteller_banner.gd")
const STORYTELLER_MODAL_SCRIPT: Script     = preload("res://scenes/ui/storyteller_modal.gd")
const LOAD_MENU_SCRIPT: Script             = preload("res://scenes/ui/load_menu.gd")
const RESUME_TOAST_SCRIPT: Script          = preload("res://scenes/ui/resume_toast.gd")
# Phase 17 — PawnDetailPanel (layer 18) and SettingsMenu (layer 26).
const PAWN_DETAIL_PANEL_SCRIPT: Script     = preload("res://scenes/ui/pawn_detail_panel.gd")
const WORKBENCH_PANEL_SCRIPT: Script       = preload("res://scenes/ui/workbench_panel.gd")
const STOCKPILE_PANEL_SCRIPT: Script       = preload("res://scenes/ui/stockpile_panel.gd")
const MEDIEVAL_THEME_SCRIPT: Script        = preload("res://scenes/ui/medieval_theme.gd")

# Built once in _ready and re-applied to any CanvasLayer-rooted Control because
# CanvasLayer doesn't propagate the root-Window theme cascade.
var _app_theme: Theme = null
const SETTINGS_MENU_SCRIPT: Script         = preload("res://scenes/ui/settings_menu.gd")
# Phase 17 (Agent B) — BuildDrawer bottom-sheet (layer 16).
const BUILD_DRAWER_SCRIPT: Script          = preload("res://scenes/ui/build_drawer.gd")
# Phase 17 (Agent C) — WorkPriorityMatrix (layer 17) and AlertsLog (layer 19).
const WORK_PRIORITY_MATRIX_SCRIPT: Script  = preload("res://scenes/ui/work_priority_matrix.gd")
const ALERTS_LOG_SCRIPT: Script            = preload("res://scenes/ui/alerts_log.gd")
# Phase 17 — DaySummaryCard end-of-day recap modal (layer 19).
const DAY_SUMMARY_CARD_SCRIPT: Script      = preload("res://scenes/ui/day_summary_card.gd")
# Phase 19 — HintOverlay top-center banner (layer 22).
const HINT_OVERLAY_SCRIPT: Script          = preload("res://scenes/ui/hint_overlay.gd")
# Phase 19 — HelpModal static reference (layer 20).
const HELP_MODAL_SCRIPT: Script            = preload("res://scenes/ui/help_modal.gd")


func _ready() -> void:
	Audit.log("main", "Phase 3 — world + AI (Decision + JobRunner + RestProvider) online.")
	# Autoloads — keep these asserts; cheap and catch a renamed-autoload
	# regression instantly.
	assert(World != null, "World autoload missing")
	assert(Sim != null, "Sim autoload missing")
	assert(GameState != null, "GameState autoload missing")
	assert(EventBus != null, "EventBus autoload missing")
	assert(Strings != null, "Strings autoload missing")
	assert(SaveSystem != null, "SaveSystem autoload missing")
	assert(Autosave != null, "Autosave autoload missing")

	# Medieval-warm Theme — assigned on the root Window first.  Cascade alone
	# doesn't reach Controls inside CanvasLayers (CanvasLayer has no theme
	# property), so we also walk the tree post-mount and apply to every Control
	# encountered.  (2026-05-16 polish pass.)
	_app_theme = MEDIEVAL_THEME_SCRIPT.build()
	get_tree().root.theme = _app_theme

	# Phase 15 — Storyteller UI layers. Runtime-instantiated so no .tscn edit is
	# needed. CanvasLayer ensures correct draw order above World/TopBar regardless
	# of parent-node position.
	var banner := CanvasLayer.new()
	banner.set_script(STORYTELLER_BANNER_SCRIPT)
	banner.name = "StorytellerBanner"
	add_child(banner)

	var modal := CanvasLayer.new()
	modal.set_script(STORYTELLER_MODAL_SCRIPT)
	modal.name = "StorytellerModal"
	add_child(modal)

	Audit.log("main", "Phase 15 — StorytellerBanner + StorytellerModal mounted.")

	# Phase 16 — Save/Load UI layers.
	var resume_toast := CanvasLayer.new()
	resume_toast.set_script(RESUME_TOAST_SCRIPT)
	resume_toast.name = "ResumeToast"
	add_child(resume_toast)

	var load_menu := CanvasLayer.new()
	load_menu.set_script(LOAD_MENU_SCRIPT)
	load_menu.name = "LoadMenu"
	add_child(load_menu)

	# Inject LoadMenu ref into TopBar so the Load button can call open()
	# without reaching into the scene tree by path.
	var top_bar = get_node_or_null("TopBar")
	if top_bar != null:
		top_bar.load_menu = load_menu

	Audit.log("main", "Phase 16 — LoadMenu + ResumeToast mounted.")

	# Phase 17 — PawnDetailPanel (layer 18) and SettingsMenu (layer 26).
	var pawn_detail_panel := CanvasLayer.new()
	pawn_detail_panel.set_script(PAWN_DETAIL_PANEL_SCRIPT)
	pawn_detail_panel.name = "PawnDetailPanel"
	add_child(pawn_detail_panel)

	# Bill-editor bottom-sheet for workbenches. Same shape as PawnDetailPanel
	# (right-anchored 360 px, layer 18); mutually exclusive with it via Selection.
	var workbench_panel := CanvasLayer.new()
	workbench_panel.set_script(WORKBENCH_PANEL_SCRIPT)
	workbench_panel.name = "WorkbenchPanel"
	add_child(workbench_panel)

	# Stockpile filter + priority editor. Right-anchored 360 px, layer 18;
	# mutually exclusive with PawnDetailPanel and WorkbenchPanel via Selection.
	var stockpile_panel := CanvasLayer.new()
	stockpile_panel.set_script(STOCKPILE_PANEL_SCRIPT)
	stockpile_panel.name = "StockpilePanel"
	add_child(stockpile_panel)

	var settings_menu := CanvasLayer.new()
	settings_menu.set_script(SETTINGS_MENU_SCRIPT)
	settings_menu.name = "SettingsMenu"
	add_child(settings_menu)

	# Inject SettingsMenu ref into TopBar so the Settings button can call open()
	# without reaching into the scene tree by path.
	if top_bar != null:
		top_bar.settings_menu = settings_menu
		if top_bar.has_method("_add_settings_btn"):
			top_bar._add_settings_btn()

	Audit.log("main", "Phase 17 — PawnDetailPanel + WorkbenchPanel + SettingsMenu mounted.")

	# Phase 17 (Agent B) — BuildDrawer bottom-sheet (layer 16).
	# Must mount AFTER the World node is ready (World._ready seeds designation_ctl).
	# Resolve the Designation controller from the World child so BuildDrawer can
	# call set_active_tool() without a get_node("/root/…") call.
	var build_drawer := CanvasLayer.new()
	build_drawer.set_script(BUILD_DRAWER_SCRIPT)
	build_drawer.name = "BuildDrawer"
	add_child(build_drawer)

	# Inject Designation ref (World child node) into the drawer.
	var world_node = get_node_or_null("World")
	if world_node != null:
		var desig = world_node.get_node_or_null("DesignationCtl")
		if desig != null:
			build_drawer.designation = desig
		else:
			Audit.log("main", "BuildDrawer: DesignationCtl not found on World — tool paint disabled")
	else:
		Audit.log("main", "BuildDrawer: World node not found — tool paint disabled")

	# Inject BuildDrawer ref into TopBar and add the Build button.
	if top_bar != null:
		top_bar.build_drawer = build_drawer
		if top_bar.has_method("_add_build_btn"):
			top_bar._add_build_btn()

	Audit.log("main", "Phase 17 (Agent B) — BuildDrawer mounted.")

	# Phase 17 (Agent C) — WorkPriorityMatrix (layer 17) and AlertsLog (layer 19).
	var work_matrix := CanvasLayer.new()
	work_matrix.set_script(WORK_PRIORITY_MATRIX_SCRIPT)
	work_matrix.name = "WorkPriorityMatrix"
	add_child(work_matrix)

	var alerts_log := CanvasLayer.new()
	alerts_log.set_script(ALERTS_LOG_SCRIPT)
	alerts_log.name = "AlertsLog"
	add_child(alerts_log)

	# Inspect tooltip — hover any tile to see what's there (pawn / wall / bed
	# / crate contents / tree progress / item stack / stockpile filter).
	# Layer 50: above world, below modals (which sit at 100+).
	var inspect := CanvasLayer.new()
	inspect.set_script(preload("res://scenes/ui/inspect_tooltip.gd"))
	inspect.name = "InspectTooltip"
	add_child(inspect)

	# Inject refs into TopBar and add Work + Log buttons to ButtonRow.
	if top_bar != null:
		top_bar.work_priority_matrix = work_matrix
		top_bar.alerts_log_panel = alerts_log
		if top_bar.has_method("_add_work_log_btns"):
			top_bar._add_work_log_btns()

	Audit.log("main", "Phase 17 (Agent C) — WorkPriorityMatrix + AlertsLog mounted.")

	# Phase 17 — DaySummaryCard (layer 19) — auto-opens on day_ended signal.
	var day_summary_card := CanvasLayer.new()
	day_summary_card.set_script(DAY_SUMMARY_CARD_SCRIPT)
	day_summary_card.name = "DaySummaryCard"
	add_child(day_summary_card)

	Audit.log("main", "Phase 17 — DaySummaryCard mounted.")

	# Phase 19 — HintOverlay top-center banner (layer 22).
	# HintOverlay._ready() registers itself with HintSystem autoload so the
	# autoload never has to find_child() the tree at call time.
	var hint_overlay := CanvasLayer.new()
	hint_overlay.set_script(HINT_OVERLAY_SCRIPT)
	hint_overlay.name = "HintOverlay"
	add_child(hint_overlay)

	# Phase 19 — HelpModal static reference panel (layer 20).
	# Subscribes to EventBus.help_requested in its own _ready; no injection needed.
	var help_modal := CanvasLayer.new()
	help_modal.set_script(HELP_MODAL_SCRIPT)
	help_modal.name = "HelpModal"
	add_child(help_modal)

	Audit.log("main", "Phase 19 — HintOverlay + HelpModal mounted.")

	# Apply the medieval theme to every Control under each CanvasLayer.
	# CanvasLayers interrupt the root-Window theme cascade so we have to seed
	# each one explicitly.  Defer one frame so panels that build their UI in
	# _ready (PawnDetailPanel, WorkbenchPanel, BuildDrawer) finish first.
	call_deferred("_apply_theme_to_canvas_layers")

	# Accessibility — live-update the global theme font size when settings change.
	EventBus.settings_changed.connect(_on_settings_changed)


## Walks the scene tree and assigns _app_theme to every Control directly under
## a CanvasLayer (the topmost Control in each layer's branch).  From there the
## standard Control-to-Control cascade carries the theme to all descendants.
## Also catches popups and modals that mount later via child_entered_tree.
func _apply_theme_to_canvas_layers() -> void:
	for c in get_children():
		if c is CanvasLayer:
			_seed_layer_theme(c)
			# Watch for late additions (popup menus, modals).
			if not c.child_entered_tree.is_connected(_on_layer_child_added):
				c.child_entered_tree.connect(_on_layer_child_added)


func _seed_layer_theme(layer: CanvasLayer) -> void:
	for c in layer.get_children():
		if c is Control and c.theme == null:
			c.theme = _app_theme


func _on_layer_child_added(node: Node) -> void:
	if node is Control and node.theme == null:
		node.theme = _app_theme


## Accessibility: re-scale the global theme default_font_size when the player
## toggles the "Larger Text" checkbox.  Mutating the shared Theme Resource
## triggers Godot's Theme.changed signal, which re-lays-out every Control that
## inherits this theme — no per-panel wiring needed for regular Labels.
## Panels with hardcoded add_theme_font_size_override calls are unaffected here;
## they handle their own overrides by listening to EventBus.settings_changed.
func _on_settings_changed() -> void:
	if _app_theme == null:
		return
	var base_size: int = 14
	_app_theme.default_font_size = int(round(float(base_size) * GameState.get_font_scale()))
