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

/**
 * <agent-artifact-ui> — Inline container for a structured agent artifact.
 *
 * Wraps an artifact (A2UI UI, JSON blob, ticket, code, etc.) with a compact
 * header showing a title + icon + optional kind badge, and two action slots:
 * "primary" (e.g. "Open in canvas") and "secondary" (e.g. "Download"). The
 * artifact body goes in the default slot.
 *
 * The host can attach any node (code-ui, canvas-ui, div, etc.) as the body.
 *
 * Usage:
 *   <agent-artifact-ui title="product-card" kind="A2UI" icon="layout">
 *     <button-ui slot="primary" text="Open in canvas" icon="arrows-out-simple"></button-ui>
 *     <button-ui slot="secondary" text="Copy" icon="copy"></button-ui>
 *     <code-ui language="json">{…}</code-ui>
 *   </agent-artifact-ui>
 *
 * Attributes:
 *   title       — header title (string)
 *   kind        — small badge, e.g. "A2UI", "JSON", "TICKET" (value is
 *                 normalized to uppercase before rendering)
 *   icon        — icon-ui name for the header
 *   collapsed   — start collapsed (body hidden)
 *   tone        — neutral (default) | accent | warning | danger
 *
 * Events:
 *   artifact-toggle — detail: { collapsed }
 */

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

const TONE_TO_BADGE_VARIANT = {
  neutral: 'default',
  accent:  'accent',
  warning: 'warning',
  danger:  'danger',
};

export class UIAgentArtifact extends UIElement {
  static properties = {
    title:     { type: String,  default: '', reflect: true },
    kind:      { type: String,  default: '', reflect: true },
    icon:      { type: String,  default: '', reflect: true },
    collapsed: { type: Boolean, default: false, reflect: true },
    tone:      { type: String,  default: 'neutral', reflect: true },
  };

  // §205 (v0.5.7): dynamic caret icons stamped on collapse/expand state
  // transition (agent-artifact.class.js:119+188). Per FEEDBACK-16 §1 + §209 slot-11 ternary-
  // walker discovery. Note: `this.icon` consumer-supplied — not declared here.
  static requiredIcons = ['caret-right', 'caret-down'];

  static template = () => null;

  #headerEl = null;
  #iconEl = null;
  #titleEl = null;
  #kindEl = null;
  #caretEl = null;
  #bodyEl = null;

  connected() {
    this.#build();
  }

  disconnected() {
    this.#headerEl?.removeEventListener('click', this.#onHeaderClick);
    this.#headerEl?.removeEventListener('keydown', this.#onHeaderKey);
    this.#headerEl = this.#iconEl = this.#titleEl = null;
    this.#kindEl = this.#caretEl = this.#bodyEl = null;
  }

  #onHeaderClick = (e) => {
    // Ignore clicks that land on header action buttons
    if (e.target.closest('[slot="primary"], [slot="secondary"]')) return;
    this.collapsed = !this.collapsed;
    this.dispatchEvent(new CustomEvent('artifact-toggle', {
      bubbles: true, detail: { collapsed: this.collapsed },
    }));
    this.render();
  };

  // Keyboard activation — Space/Enter toggle (matches role="button" semantics).
  #onHeaderKey = (e) => {
    if (e.key === ' ' || e.key === 'Enter') {
      // Don't fire when the focus is on a slotted action button — let those
      // handle their own activation.
      if (e.target.closest('[slot="primary"], [slot="secondary"]')) return;
      e.preventDefault();
      this.#onHeaderClick(e);
    }
  };

  render() {
    if (!this.#headerEl) return;

    if (this.#iconEl) {
      if (this.icon) { this.#iconEl.setAttribute('name', this.icon); this.#iconEl.hidden = false; }
      else { this.#iconEl.hidden = true; }
    }
    if (this.#titleEl) {
      this.#titleEl.textContent = this.title || '';
      this.#titleEl.hidden = !this.title;
    }
    if (this.#kindEl) {
      this.#kindEl.setAttribute('text', (this.kind || '').toUpperCase());
      this.#kindEl.setAttribute('variant', TONE_TO_BADGE_VARIANT[this.tone] || 'default');
      this.#kindEl.hidden = !this.kind;
    }
    if (this.#caretEl) {
      this.#caretEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');
    }
    if (this.#bodyEl) {
      this.#bodyEl.hidden = this.collapsed;
    }
    if (this.#headerEl) {
      this.#headerEl.setAttribute('aria-expanded', String(!this.collapsed));
    }
  }

  #build() {
    // We operate in a slotted model: the author's children that match
    // slot="primary"/slot="secondary" live in the header; the rest is body.
    // We build scaffolding DOM around those children without reparenting.
    //
    // To keep the Light-DOM approach consistent, we wrap existing children
    // into a body container if one isn't already present.

    // Partition the author's children by LOGICAL slot, piercing the template
    // engine's display:contents / role="presentation" wrapper spans. A consumer
    // that interpolates the action buttons — `${actions.map(a => html`<button-ui
    // slot="primary">…`)}` — gets them nested in wrapper spans (core/template.js
    // wrap()), so the old `:scope > [slot="primary"]` direct-child grab returned
    // nothing and `innerHTML = ''` stranded them in the body. This is the
    // wrapper-trap class (FB-92/96/98); walk + pierce so wrapped action buttons
    // reach the header actions cluster. Wrappers are flattened (display:contents
    // is layout-transparent); everything non-action becomes body.
    const primaryBtns = [];
    const secondaryBtns = [];
    const bodyNodes = [];
    const isWrapper = (el) =>
      el.getAttribute('role') === 'presentation' || el.style?.display === 'contents';
    const partition = (nodes) => {
      for (const n of nodes) {
        if (n.nodeType === 1) {
          const el = /** @type {Element} */ (n);
          if (isWrapper(el)) { partition(el.childNodes); continue; } // pierce; drop the wrapper
          const slot = el.getAttribute('slot') || '';
          if (slot === 'primary') { primaryBtns.push(el); continue; }
          if (slot === 'secondary') { secondaryBtns.push(el); continue; }
        }
        bodyNodes.push(n);
      }
    };
    partition(Array.from(this.childNodes));

    // Clear — we'll rebuild around the captured (now-detached) children.
    this.innerHTML = '';

    // Header — keyboard-focusable button-style row that toggles collapsed.
    // role/tabindex make Space/Enter activate it the same as click.
    this.#headerEl = document.createElement('div');
    this.#headerEl.setAttribute('data-artifact-header', '');
    this.#headerEl.setAttribute('role', 'button');
    this.#headerEl.setAttribute('tabindex', '0');
    this.#headerEl.setAttribute('aria-expanded', String(!this.collapsed));
    this.#headerEl.addEventListener('click', this.#onHeaderClick);
    this.#headerEl.addEventListener('keydown', this.#onHeaderKey);

    this.#iconEl = document.createElement('icon-ui');
    this.#iconEl.setAttribute('data-artifact-icon', '');
    this.#iconEl.setAttribute('color', 'muted');
    if (this.icon) this.#iconEl.setAttribute('name', this.icon);
    else this.#iconEl.hidden = true;

    this.#titleEl = document.createElement('span');
    this.#titleEl.setAttribute('data-artifact-title', '');
    if (this.title) this.#titleEl.textContent = this.title;
    else this.#titleEl.hidden = true;

    this.#kindEl = document.createElement('badge-ui');
    this.#kindEl.setAttribute('data-artifact-kind', '');
    this.#kindEl.setAttribute('size', 'sm');
    this.#kindEl.setAttribute('variant', TONE_TO_BADGE_VARIANT[this.tone] || 'default');
    if (this.kind) this.#kindEl.setAttribute('text', this.kind.toUpperCase());
    else this.#kindEl.hidden = true;

    const actions = document.createElement('span');
    actions.setAttribute('data-artifact-actions', '');
    for (const btn of secondaryBtns) actions.appendChild(btn);
    for (const btn of primaryBtns) actions.appendChild(btn);

    this.#caretEl = document.createElement('icon-ui');
    this.#caretEl.setAttribute('color', 'muted');
    this.#caretEl.setAttribute('data-artifact-caret', '');
    this.#caretEl.setAttribute('name', this.collapsed ? 'caret-right' : 'caret-down');

    this.#headerEl.append(this.#iconEl, this.#titleEl, this.#kindEl, actions, this.#caretEl);

    // Body
    this.#bodyEl = document.createElement('div');
    this.#bodyEl.setAttribute('data-artifact-body', '');
    for (const n of bodyNodes) this.#bodyEl.appendChild(n);
    if (this.collapsed) this.#bodyEl.hidden = true;

    this.append(this.#headerEl, this.#bodyEl);
  }
}
