/**
 * Non-side-effect class export for `<page-ui>`.
 *
 * Importing this file gives you the class(es) without auto-registering the tag.
 * Useful for test isolation, subclassing with tag-name override, or selective
 * composition.
 *
 * The auto-register path stays at `@adia-ai/web-components/components/page`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * <page-ui> — Page container.
 *
 * Holds page-level chrome — header / content / footer — and manages
 * max-width clamps, padding scale, optional scroll-container, and an
 * optional sticky-header sentinel. Compose with the slot primitives
 * (`<header-ui>`, `<section-ui>`, `<footer-ui>`); the page's @scope
 * rules style them.
 *
 * Authoring:
 *   <page-ui sticky-header max-width="prose" padding="6">
 *     <header-ui>...</header-ui>     <!-- page title + actions -->
 *     <section-ui>...</section-ui>   <!-- main content -->
 *     <footer-ui>...</footer-ui>     <!-- optional -->
 *   </page-ui>
 *
 * Attributes:
 *   scroll          — boolean. Page is the scroll container (overflow-y: auto).
 *   max-width       — '' | 'prose' (65ch) | 'narrow' (80ch) | 'wide' (1080px) | 'full' (100%).
 *   padding         — '' | '0'..'8' (mapped to --a-space-N).
 *   sticky-header   — boolean. Installs IntersectionObserver sentinel before the
 *                     first <header> / <header-ui> child; sets [data-header-stuck]
 *                     on the page when the sentinel scrolls out of view.
 *
 * ADR: .brain/adrs/0009-promote-app-shell-and-page-to-components.md.
 */

import { UIElement } from '../../core/element.js';

export class UIPage extends UIElement {
  static properties = {
    scroll:       { type: Boolean, default: false, reflect: true },
    maxWidth:     { type: String,  default: '',    attribute: 'max-width', reflect: true },
    padding:      { type: String,  default: '',    reflect: true },
    stickyHeader: { type: Boolean, default: false, attribute: 'sticky-header', reflect: true },
  };

  static template = () => null;

  #sentinel = null;
  #observer = null;

  connected() {
    if (this.stickyHeader) this.#installSticky();
  }

  disconnected() {
    this.#teardownSticky();
  }

  render() {
    // Sticky-header attribute changes between renders → install / tear down.
    if (this.stickyHeader && !this.#sentinel) this.#installSticky();
    if (!this.stickyHeader && this.#sentinel) this.#teardownSticky();
  }

  #installSticky() {
    const header = this.querySelector(':scope > :is(header, header-ui)');
    if (!header) return;

    if (!this.#sentinel) {
      this.#sentinel = document.createElement('div');
      this.#sentinel.setAttribute('data-page-sentinel', '');
      this.#sentinel.style.cssText = 'height: 0; width: 0; pointer-events: none;';
      header.insertAdjacentElement('beforebegin', this.#sentinel);
    }

    if (!this.#observer) {
      this.#observer = new IntersectionObserver((entries) => {
        this.toggleAttribute('data-header-stuck', !entries[0].isIntersecting);
      }, { threshold: 0 });
    }

    this.#observer.observe(this.#sentinel);
  }

  #teardownSticky() {
    this.#observer?.disconnect();
    this.#observer = null;
    this.#sentinel?.remove();
    this.#sentinel = null;
    this.removeAttribute('data-header-stuck');
  }
}
