// Field-level "?" reference dialogs. Sibling to why-panels.js: why-panels are always-visible
// section prose ("why this works"); this is an on-demand, per-field reference library ("what are
// my options"). See FIELD_HELP_SPEC.md (deleted after implementation) for the design rationale.

import { HELP_TOPICS } from "./field-help-content.js";

export function initFieldHelp({ getPlan, getTempUnit, getMachineProfile }) {
	const dialog = document.getElementById("field-help-dialog");
	if (!dialog) return;
	const titleEl = document.getElementById("help-dialog-title");
	const bodyEl = document.getElementById("help-dialog-body");
	let lastTrigger = null;

	function openTopic(key, trigger) {
		const topic = HELP_TOPICS[key];
		if (!topic) return;
		lastTrigger = trigger;
		titleEl.textContent = topic.title;
		bodyEl.replaceChildren(topic.render(getPlan(), getTempUnit?.(), getMachineProfile?.()));
		bodyEl.scrollTop = 0;
		dialog.showModal();
	}

	// A button appended into a `.field-label` span is a labelable element, and a <label>
	// without an explicit `for` labels its FIRST labelable descendant in tree order — so an
	// unlabeled wrapping <label> would silently make the help button, not the input, the
	// label's control. Give the input an explicit id/for pairing before that can happen; a
	// no-op wherever the container isn't inside a <label> or is already explicitly paired.
	function ensureLabelAssociation(container) {
		const label = container.closest("label");
		if (!label || label.hasAttribute("for")) return;
		const control = label.querySelector("input, select, textarea");
		if (!control) return;
		if (!control.id)
			control.id = `fh-${(control.name || `${Math.random()}`).replace(/[^\w-]/g, "-")}`;
		label.setAttribute("for", control.id);
	}

	function makeButton(key, title) {
		const btn = document.createElement("button");
		btn.type = "button";
		btn.className = "help-btn";
		btn.dataset.helpTopic = key;
		btn.setAttribute("aria-label", `Field guide: ${title.split(" — ")[0]}`);
		btn.setAttribute("aria-haspopup", "dialog");
		btn.textContent = "?";
		// Several triggers live inside <label> elements — stop the click from also
		// focusing/toggling the label's control (radio chips especially).
		btn.addEventListener("click", (e) => {
			e.preventDefault();
			e.stopPropagation();
			openTopic(key, btn);
		});
		return btn;
	}

	for (const [key, topic] of Object.entries(HELP_TOPICS)) {
		const containers = [];
		for (const sel of topic.targets ?? [])
			containers.push(...document.querySelectorAll(`#plan-form ${sel}`));
		if (topic.place) containers.push(...topic.place());
		if (containers.length === 0)
			console.warn(`field-help: topic "${key}" resolved zero containers — its "?" button is missing.`);
		for (const container of containers) {
			ensureLabelAssociation(container);
			container.append(makeButton(key, topic.title));
		}
	}

	// Deferred: a click that closes the dialog (the ✕ button, or a backdrop click) also runs
	// the browser's own click-focuses-the-target step, which can otherwise land after — and
	// override — a synchronous focus() call made while handling that same click.
	function returnFocus() {
		const trigger = lastTrigger;
		setTimeout(() => trigger?.focus(), 0);
	}

	dialog.querySelector("[data-close-help]")?.addEventListener("click", () => {
		dialog.close();
		returnFocus();
	});
	dialog.addEventListener("click", (e) => {
		if (e.target === dialog) {
			dialog.close();
			returnFocus();
		}
	});
	// Covers every other close path (Esc, or dialog.close() called directly) — native <dialog>
	// already restores focus to the pre-showModal() element on close in current browsers; this
	// listener is the explicit fallback for engines where that isn't reliable.
	dialog.addEventListener("close", returnFocus);
}
