import { T, t } from "./utils/index.js";
export const info= {
	title: t`Scopes and Components`,
	fullTitle: t`Building Maintainable UIs with Scopes and Components`,
	description: t`Organizing UI into reusable, manageable components`,
};

import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js";
import { example } from "./components/example.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { mnemonic } from "./components/mnemonic/scopes-init.js";
import { code, pre } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
const references= {
	/** Garbage collection on MDN */
	garbage_collection: {
		title: t`MDN documentation page for Garbage collection`,
		href: "https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection",
	},
	/** Signals */
	signals: {
		title: t`Signals section on this library`,
		href: "./p04-signals#h-introducing-signals",
	}
};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
	const page_id= info.id;
	return el(simplePage, { info, pkg }).append(
		el("p").append(T`
			For state-less components we can use functions as UI components (see “Elements” page). But in real life,
			we may need to handle the component’s life-cycle and provide JavaScript the way to properly use
			the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}.
		`),
		el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
		el("p").append(T`The library therefore uses ${el("em", t`scopes`)} to provide these functionalities.`),

		el(h3, t`Understanding Host Elements and Scopes`),
		el("p").append(T`
			The ${el("strong", "host")} is the name for the element representing the component. This is typically the
			element returned by a function. To get a reference, you can use ${el("code", "scope.host()")}. To apply addons,
			just use ${el("code", "scope.host(...<addons>)")}.
		`),
		el("p").append(T`
			Scopes are primarily needed when signals are used in DOM templates (with ${el("code", "el")}, ${el("code",
				"assign")}, or ${el("code", "S.el")}). They provide a way for automatically removing signal listeners
			and cleaning up unused signals when components are removed from the DOM.
		`),
		el("div", { className: "illustration" }).append(
			el("h4", t`Component Anatomy`),
			el(pre, { content: `
				// 1. Component scope created
				el(MyComponent);

				function MyComponent() {
					// 2. access the host element (or other scope related values)
					const { host } = scope;

					// 3. Add behavior to host
					host(
						on.click(handleClick)
					);

					// 4. Return the host element
					return el("div", {
						className: "my-component"
					}).append(
						el("h2", "Title"),
						el("p", "Content"),
					);
				}
			` })
		),
		el("div", { className: "function-table" }).append(
			el("h4", t`scope.host()`),
			el("dl").append(
				el("dt", t`When called with no arguments`),
				el("dd", t`Returns a reference to the host element (the root element of your component)`),

				el("dt", t`When called with addons/callbacks`),
				el("dd", t`Applies the addons to the host element (and returns the host element)`)
			)
		),
		el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }),

		el("div", { className: "tip" }).append(
			el("p").append(T`
				${el("strong", "Best Practice:")} Always capture the host reference (or other scope related values) at
				the beginning of your component function using ${el("code", "const { host } = scope")} to avoid
				scope-related issues, especially with ${el("em", "asynchronous code")}.
			`),
			el("p").append(T`
				If you are interested in the implementation details, see Class-Based Components section.
			`)
		),
		el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),

		el(h3, t`Class-Based Components`),
		el("p").append(T`
			While functional components are the primary pattern in dd<el>, you can also create class-based components.
			For this, we implement function ${el("code", "elClass")} and use it to demonstrate implementation details
			for better understanding of the scope logic.
		`),
		el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }),

		el(h3, t`Automatic Cleanup with Scopes`),
		el("p").append(T`
			One of the most powerful features of scopes is automatic cleanup when components are removed from the DOM.
			This prevents memory leaks and ensures resources are properly released.
		`),
		el("div", { className: "illustration" }).append(
			el("h4", t`Lifecycle Flow`),
			el(pre, { content: `
				1. Component created → scope established
				2. Component added to DOM → connected event
				3. Component interactions happen
				4. Component removed from DOM → disconnected event
				5. Automatic cleanup of:
					- Event listeners (browser)
					- Signal subscriptions (dd<el> and browser)
					- Custom cleanup code (dd<el> and user)
			` })
		),
		el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }),

		el("div", { className: "note" }).append(
			el("p").append(T`
				In this example, when you click "Remove", the component is removed from the DOM, and all its associated
				resources are automatically cleaned up, including ${el("em",
					"the signal subscription that updates the text content")}. This happens because the library
				internally registers a disconnected event handler on the host element.
			`)
		),

		el(h3, t`Declarative vs Imperative Components`),
		el("p").append(T`
			The library DOM API and signals work best when used declaratively. It means you split your app’s logic
			into three parts as introduced in ${el("a", { textContent: "Signals (3PS)", ...references.signals })}.
		`),
		el("div", { className: "note" }).append(
			el("p").append(T`
				Strictly speaking, the imperative way of using the library is not prohibited. Just be careful to avoid
				mixing the declarative approach (using signals) with imperative manipulation of elements.
			`)
		),
		el("div", { className: "tabs" }).append(
			el("div", { className: "tab", dataTab: "declarative" }).append(
				el("h4", t`✅ Declarative Approach`),
				el("p", t`Define what your UI should look like based on state:`),
				el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id })
			),
			el("div", { className: "tab", dataTab: "imperative" }).append(
				el("h4", t`⚠️ Imperative Approach`),
				el("p", t`Manually update the DOM in response to events:`),
				el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id })
			),
			el("div", { className: "tab", dataTab: "mixed" }).append(
				el("h4", t`❌ Mixed Approach`),
				el("p", t`This approach should be avoided:`),
				el(code, { src: fileURL("./components/examples/scopes/mixed.js"), page_id })
			)
		),

		el(h3, t`Best Practices for Scopes and Components`),
		el("ol").append(
			el("li").append(T`
				${el("strong", "Capture host early:")} Use ${el("code", "const { host } = scope")} at component start
			`),
			el("li").append(T`
				${el("strong", "Define signals as constants:")} ${el("code", "const counter = S(0);")}
			`),
			el("li").append(T`
				${el("strong", "Prefer declarative patterns:")} Use signals to drive UI updates rather than manual DOM
				manipulation
			`),
			el("li").append(T`
				${el("strong", "Keep components focused:")} Each component should do one thing well
			`),
			el("li").append(T`
				${el("strong", "Add explicit cleanup:")} For resources not managed by dd<el>, use ${el("code",
					"on.disconnected")}
			`)
		),

		el("div", { className: "troubleshooting" }).append(
			el("h4", t`Common Scope Pitfalls`),
			el("dl").append(
				el("dt", t`Losing host reference in async code`),
				el("dd", t`Store host reference early with const { host } = scope`),

				el("dt", t`Memory leaks from custom resources`),
				el("dd", t`Use host(on.disconnected(cleanup)) for manual resource cleanup`),

				el("dt", t`Event handlers with incorrect 'this'`),
				el("dd", t`Use arrow functions or .bind() to preserve context`),

				el("dt", t`Mixing declarative and imperative styles`),
				el("dd", t`Choose one approach and be consistent throughout a component(s)`)
			)
		),

		el(mnemonic)
	);
}