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

import { UIElement } from '../../core/element.js';
import { registry } from '@adia-ai/a2ui-runtime';
import '../tabs/tabs.js';
import '../tabs/tab.js';
import '../code/code.js';

/**
 * <inspector-ui> — Developer tools pane for inspecting A2UI state.
 *
 * Composes <tabs-ui> with four panes:
 *   Catalog  — A2UI registry type-to-tag mapping
 *   Surface  — current surface schema (JSON)
 *   Messages — message log
 *   Code     — rendered HTML
 *
 * Usage (declarative — initial surface payload):
 *   <inspector-ui>
 *     { "hello": "world" }
 *   </inspector-ui>
 *
 * Usage (imperative):
 *   const inspector = document.querySelector('inspector-ui');
 *   inspector.update(schema, messages);
 *   inspector.setHTML(renderedHTML);
 *
 * Attributes:
 *   value — active tab: 'catalog' | 'surface' | 'messages' | 'code'
 *           (default: 'surface')
 */
export class UIInspector extends UIElement {
  static properties = {
    value: { type: String, default: 'surface', reflect: true },
  };

  static template = () => null;

  #tabs = null;
  #panes = {};

  connected() {
    const declarative = this.textContent?.trim() || '';
    this.innerHTML = '';
    this.#build(declarative);
  }

  disconnected() {
    this.#tabs?.removeEventListener('change', this.#onChange);
    this.#tabs = null;
    this.#panes = {};
  }

  render() {
    if (this.#tabs && this.#tabs.getAttribute('value') !== this.value) {
      this.#tabs.setAttribute('value', this.value);
    }
  }

  #onChange = (e) => {
    if (e.detail?.value && e.detail.value !== this.value) {
      this.value = e.detail.value;
    }
  };

  #build(initialSurface) {
    const catalogText = [...registry.entries()]
      .map(([type, tag]) => `${type} → <${tag}>`)
      .join('\n');

    this.#tabs = document.createElement('tabs-ui');
    this.#tabs.setAttribute('value', this.value || 'surface');
    this.#tabs.addEventListener('change', this.#onChange);

    this.#addPane('catalog', `Catalog (${registry.size})`, catalogText);
    this.#addPane('surface', 'Surface', initialSurface || '{}', { language: 'json' });
    this.#addPane('messages', 'Messages', '(no messages)');
    this.#addPane('code', 'Code', '(empty)', { language: 'html', lineNumbers: true });

    this.appendChild(this.#tabs);
  }

  #addPane(value, text, body, opts = {}) {
    const tab = document.createElement('tab-ui');
    tab.setAttribute('value', value);
    tab.setAttribute('text', text);

    const pane = document.createElement('code-ui');
    if (opts.language) pane.setAttribute('language', opts.language);
    if (opts.lineNumbers) pane.setAttribute('line-numbers', '');
    pane.setAttribute('text', body);

    tab.appendChild(pane);
    this.#tabs.appendChild(tab);
    this.#panes[value] = pane;
  }

  /**
   * Refresh the surface state and message log.
   * @param {object} schema — surface schema object (JSON-serializable)
   * @param {object[]} messages — array of A2UI messages
   */
  update(schema, messages) {
    if (this.#panes.surface) {
      this.#panes.surface.setAttribute('text', JSON.stringify(schema, null, 2));
    }
    if (this.#panes.messages) {
      const log = Array.isArray(messages) && messages.length
        ? messages
            .map((m, i) => `${i + 1}. ${m.type || m.messageType || 'unknown'}${m.surfaceId ? ` [${m.surfaceId}]` : ''}`)
            .join('\n')
        : '(no messages)';
      this.#panes.messages.setAttribute('text', log);
    }
    const msgTab = this.#tabs?.querySelector('tab-ui[value="messages"]');
    if (msgTab) {
      const count = Array.isArray(messages) ? messages.length : 0;
      msgTab.setAttribute('text', `Messages (${count})`);
    }
  }

  /**
   * Update the Code tab.
   * @param {string} html — HTML string to display
   */
  setHTML(html) {
    if (this.#panes.code) {
      this.#panes.code.setAttribute('text', html || '(empty)');
    }
  }
}
