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

/**
 * <accordion-ui>
 *   <accordion-item-ui text="Section 1">Content for section 1</accordion-item-ui>
 *   <accordion-item-ui text="Section 2">Content for section 2</accordion-item-ui>
 * </accordion-ui>
 *
 * Accordion container + item pair.
 * Container manages single/multiple open states.
 * Items handle their own expand/collapse toggle.
 *
 * Events (on accordion-item-ui):
 *   toggle — { detail: { open } }
 */

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

// ── Accordion Container ────────────────────────────────────────

export class UIAccordion extends UIElement {
  // §154 (v0.5.3): Phosphor icons this primitive auto-stamps (without
  // consumer markup). Aggregated by installIconLoadersForRegistered()
  // across all defined elements. Audited by check-required-icons.mjs
  // (slot 11). Per FEEDBACK-06 §4 + FEEDBACK-07 §4.
  static requiredIcons = ['caret-down'];

  static properties = {
    multiple: { type: Boolean, default: false, reflect: true },
  };

  static template = () => null;

  connected() {
    this.addEventListener('toggle', this.#onItemToggle);
  }

  disconnected() {
    this.removeEventListener('toggle', this.#onItemToggle);
  }

  #onItemToggle = (e) => {
    if (this.multiple) return;

    const target = e.target;
    if (!target.open) return;

    // Close other items
    const items = this.querySelectorAll('accordion-item-ui');
    for (const item of items) {
      if (item !== target && item.open) {
        item.open = false;
      }
    }
  };
}

export class UIAccordionItem extends UIElement {
  static properties = {
    text: { type: String,  default: '', reflect: true },
    open: { type: Boolean, default: false, reflect: true },
  };

  static template = () => null;

  #bound = false;

  connected() {
    // Stamp header if not present
    if (!this.querySelector('[slot="header"]')) {
      const header = document.createElement('div');
      header.setAttribute('slot', 'header');

      const label = document.createElement('span');
      label.setAttribute('slot', 'header-text');
      header.appendChild(label);

      const caret = document.createElement('icon-ui');
      caret.setAttribute('name', 'caret-down');
      caret.setAttribute('slot', 'caret');
      header.appendChild(caret);

      this.prepend(header);
    }

    // Stamp content wrapper if not present
    if (!this.querySelector('[slot="body"]')) {
      const body = document.createElement('div');
      body.setAttribute('slot', 'body');

      // Move non-slotted children into body
      const children = [...this.childNodes].filter(n => {
        if (n.nodeType === 1) return !n.hasAttribute('slot');
        return n.nodeType === 3 && n.textContent.trim();
      });
      for (const child of children) body.appendChild(child);

      this.appendChild(body);
    }

    if (!this.#bound) {
      this.#bound = true;
      this.addEventListener('click', this.#onClick);
    }
  }

  disconnected() {
    this.removeEventListener('click', this.#onClick);
    this.#bound = false;
  }

  render() {
    const label = this.querySelector('[slot="header-text"]');
    if (label) label.textContent = this.text;
  }

  #onClick = (e) => {
    const header = this.querySelector('[slot="header"]');
    if (!header || !header.contains(e.target)) return;
    // FEEDBACK-16 §2 (v0.5.7 §206): skip toggle when click originates inside an
    // action slot or an opt-out marker. Lets consumers author action buttons in
    // custom headers without bubbling-toggle UX. Slot vocabulary matches
    // drawer-ui + pane-ui.
    if (e.target.closest('[slot="action"], [slot="actions"], [data-no-toggle]')) return;

    this.open = !this.open;
    this.dispatchEvent(new CustomEvent('toggle', {
      bubbles: true,
      detail: { open: this.open },
    }));
  };
}
