/**
 * Non-side-effect class export for `<nav-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/nav`
 * (which imports this file + calls `defineIfFree()`).
 *
 * @see ../../USAGE.md#registration--auto-vs-explicit
 */

/**
 * <nav-ui> — Navigation rail (consolidated primary + section variants).
 *
 * Consolidates the prior `app-nav-ui` + `section-nav-ui` dual-family
 * per ADR-0015 § Nav consolidation. Variant drives visual treatment;
 * behavior is unified.
 *
 * Variants:
 *   primary  — default. App sidebar. ResizeObserver collapses to icon-only
 *              below 96px container width or when [collapsed] set; groups
 *              open a popover with their children when collapsed.
 *   section  — subnav rail. Quieter chrome; no collapse behavior.
 *              Optional [heading] attribute renders an uppercase label
 *              via ::before pseudo (CSS-only).
 *
 * Structure:
 *   <nav-ui>
 *     <nav-group-ui icon="gear" text="Settings" badge="3">
 *       <nav-item-ui text="General" value="/settings/general"></nav-item-ui>
 *     </nav-group-ui>
 *     <nav-item-ui icon="user" text="Profile" value="/profile"></nav-item-ui>
 *   </nav-ui>
 *
 *   <nav-ui variant="section" heading="On this page">
 *     <nav-item-ui text="Overview" value="#overview"></nav-item-ui>
 *   </nav-ui>
 *
 * Event: nav-select (bubbles from nav-item-ui). detail: { item, text, value }
 */

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

export class UINav extends UIElement {
  static properties = {
    variant:   { type: String,  default: 'primary', reflect: true },
    collapsed: { type: Boolean, default: false,     reflect: true },
    divider:   { type: Boolean, default: false,     reflect: true },
    heading:   { type: String,  default: '',        reflect: true },
  };

  static template = () => null;

  #ro = null;

  connected() {
    this.setAttribute('role', 'navigation');
    if (this.heading) this.setAttribute('aria-label', this.heading);
    this.addEventListener('click', this.#onClick);

    // ResizeObserver only meaningful for primary variant — section is static.
    if (this.variant !== 'section') {
      this.#ro = new ResizeObserver(() => this.#updateTooltips());
      this.#ro.observe(this);
    }
  }

  render() {
    if (this.heading) this.setAttribute('aria-label', this.heading);
    else this.removeAttribute('aria-label');
    if (this.variant !== 'section') this.#updateTooltips();
  }

  #updateTooltips() {
    const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
    for (const group of this.querySelectorAll(':scope > nav-group-ui')) {
      const header = group.querySelector(':scope > [slot="header"]');
      if (header) header.title = isCollapsed ? group.text : '';
    }
    for (const item of this.querySelectorAll(':scope > nav-item-ui')) {
      item.title = isCollapsed ? item.text : '';
    }
  }

  get selectedItem() {
    return this.querySelector('nav-item-ui[selected]');
  }

  select(item) {
    const prev = this.selectedItem;
    if (prev && prev !== item) prev.removeAttribute('selected');
    if (item) {
      item.setAttribute('selected', '');
      this.dispatchEvent(new CustomEvent('nav-select', {
        bubbles: true,
        detail: { item, text: item.text, value: item.value },
      }));
    }
  }

  toggle() {
    if (this.variant === 'section') return; // no-op for section variant
    this.collapsed = !this.collapsed;
  }

  #onClick = (e) => {
    const item = e.target.closest('nav-item-ui');
    if (item && this.contains(item)) {
      if (item.disabled) return;
      this.select(item);
      this.#flushHoverState();
      return;
    }

    // Group expand/popover — primary variant only.
    if (this.variant === 'section') return;

    const group = e.target.closest('nav-group-ui');
    if (group && this.contains(group)) {
      const isCollapsed = this.collapsed || this.getBoundingClientRect().width <= 96;
      if (isCollapsed) {
        group.showPopover?.();
      } else {
        const header = group.querySelector(':scope > [slot="header"]');
        if (header && (e.target === header || header.contains(e.target))) {
          group.open = !group.open;
        }
      }
    }
  };

  // Safari macOS leaves :hover stuck on items the cursor passed through
  // when the DOM mutates during click+route navigation. Toggling pointer-
  // events forces re-evaluation of hover state on next paint.
  // See docs/BROWSER-COMPAT.md §3a.
  #flushHoverState() {
    this.style.pointerEvents = 'none';
    requestAnimationFrame(() => {
      this.style.pointerEvents = '';
    });
  }

  disconnected() {
    this.removeEventListener('click', this.#onClick);
    this.#ro?.disconnect();
    this.#ro = null;
  }
}
