/**
 * <agent-trace-ui> — Collapsible metrics + training-feedback panel.
 *
 * A trailing artifact for agent responses. Summary row shows a handful of
 * pills (colored dot + label + value); body expands to a label/value/aux grid
 * plus an optional training-feedback block of icon + line entries.
 *
 * JS API:
 *   const trace = document.createElement('agent-trace-ui');
 *
 *   trace.pills = [
 *     { label: 'match',  value: '90%', tone: 'success' },
 *     { label: 'intent', value: '7%',  tone: 'danger'  },
 *     { label: '94/100' },                                  // plain text pill
 *   ];
 *
 *   trace.metrics = [
 *     { label: 'Pattern',    value: '90%',    aux: 'product-card' },
 *     { label: 'Intent',     value: '7%',     aux: 'pro' },
 *     { label: 'Generation', value: '85%',    aux: '31 components' },
 *     { label: 'Validation', value: '94/100' },
 *   ];
 *
 *   trace.feedback = [
 *     { icon: 'warning',      tone: 'warning', text: 'Low intent confidence' },
 *     { icon: 'check-circle', tone: 'success', text: 'Healthy — candidate for promotion' },
 *   ];
 *
 * Attributes:
 *   open    — start expanded
 *   label   — header text when no pills (default: "Trace")
 *
 * Events:
 *   trace-toggle — summary opened/closed
 */

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

class UIAgentTrace 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-right', 'circle-fill'];

  static properties = {
    // agent-* family is default-visible disclosure (see component-token-contract.md
    // §"Toggle state naming"). Use `collapsed` to hide; bare element shows.
    collapsed: { type: Boolean, default: false, reflect: true },
    label:     { type: String,  default: '',    reflect: true },
  };

  static template = () => null;

  #pills = [];
  #metrics = [];
  #feedback = [];
  #rootEl = null;

  get pills()    { return this.#pills; }
  set pills(v)   { this.#pills    = Array.isArray(v) ? v.slice() : []; this.#render(); }

  get metrics()  { return this.#metrics; }
  set metrics(v) { this.#metrics  = Array.isArray(v) ? v.slice() : []; this.#render(); }

  get feedback()    { return this.#feedback; }
  set feedback(v)   { this.#feedback = Array.isArray(v) ? v.slice() : []; this.#render(); }

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

  disconnected() {
    this.#rootEl?.removeEventListener('toggle', this.#onToggle);
    this.#rootEl = null;
  }

  #onToggle = () => {
    this.collapsed = !this.#rootEl.hasAttribute('open');
    this.dispatchEvent(new CustomEvent('trace-toggle', {
      bubbles: true, detail: { collapsed: this.collapsed },
    }));
  };

  #buildShell() {
    this.innerHTML = '';
    this.#rootEl = document.createElement('details');
    this.#rootEl.setAttribute('data-trace-root', '');
    if (!this.collapsed) this.#rootEl.setAttribute('open', '');
    this.#rootEl.addEventListener('toggle', this.#onToggle);
    this.appendChild(this.#rootEl);
    this.#render();
  }

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

    const pillsHTML = this.#pills.length
      ? this.#pills.map(p => this.#renderPill(p)).join('<span data-trace-sep>·</span>')
      : `<span>${escapeText(this.label || 'Trace')}</span>`;

    const hasAux = this.#metrics.some(m => m.aux != null && String(m.aux).trim() !== '');
    const hasAnyDetails = this.#metrics.some(m => this.#hasDetails(m));

    const headerRow = this.#metrics.length ? `
      <div data-trace-headers>
        <span data-trace-header>Stage</span>
        <span data-trace-header>Score</span>
        <span data-trace-header>${hasAux ? 'Detail' : ''}</span>
        ${hasAnyDetails ? '<span data-trace-header-spacer aria-hidden="true"></span>' : ''}
      </div>
    ` : '';

    const rowsHTML = this.#metrics.map(m => this.#renderRow(m, hasAnyDetails)).join('');

    const feedbackHTML = this.#feedback.length ? `
      <div data-trace-feedback>
        <div data-trace-feedback-label>Training feedback</div>
        ${this.#feedback.map(f => `
          <div data-trace-line>
            <icon-ui name="${escapeAttr(f.icon || 'circle')}" color="${escapeAttr(f.tone || 'muted')}"></icon-ui>
            <span>${escapeText(f.text || '')}</span>
          </div>
        `).join('')}
      </div>
    ` : '';

    this.#rootEl.innerHTML = `
      <summary>
        <span data-trace-status>${pillsHTML}</span>
        <icon-ui name="caret-right" color="muted" size="sm" data-trace-caret></icon-ui>
      </summary>
      <div data-trace-body>
        ${this.#metrics.length ? `<div data-trace-rows${hasAnyDetails ? ' data-has-details' : ''}>${headerRow}${rowsHTML}</div>` : ''}
        ${feedbackHTML}
      </div>
    `;
  }

  #hasDetails(m) {
    const d = m?.details;
    if (Array.isArray(d)) return d.length > 0;
    if (typeof d === 'string') return d.trim().length > 0;
    return false;
  }

  #renderRow(m, hasAnyDetails) {
    const label = escapeText(m.label || '');
    const value = escapeText(m.value != null ? String(m.value) : '');
    const aux   = escapeText(m.aux != null ? String(m.aux) : '');
    const hasDetails = this.#hasDetails(m);

    const summary = `
      <span data-trace-label>${label}</span>
      <span data-trace-value>${value}</span>
      <span data-trace-aux>${aux}</span>
      ${hasAnyDetails
        ? (hasDetails
            ? '<icon-ui name="caret-right" color="muted" data-trace-row-caret></icon-ui>'
            : '<span data-trace-row-caret-spacer aria-hidden="true"></span>')
        : ''}
    `;

    if (!hasDetails) {
      return `<div data-trace-row>${summary}</div>`;
    }

    return `
      <details data-trace-row>
        <summary>${summary}</summary>
        <div data-trace-row-body>${this.#renderDetails(m.details)}</div>
      </details>
    `;
  }

  #renderDetails(details) {
    if (Array.isArray(details)) {
      return `
        <dl data-trace-dl>
          ${details.map(d => `
            <dt>${escapeText(d.label || '')}</dt>
            <dd>${escapeText(d.value != null ? String(d.value) : '')}</dd>
          `).join('')}
        </dl>
      `;
    }
    if (typeof details === 'string') {
      // Trust the caller for HTML; render as-is. If you want escaping, pass an array.
      return details;
    }
    return '';
  }

  #renderPill(p) {
    const tone = p.tone || 'neutral';
    const color = {
      success: 'var(--a-success-strong)',
      warning: 'var(--a-warning-strong)',
      danger:  'var(--a-danger-strong)',
      info:    'var(--a-accent-strong)',
      neutral: 'var(--a-fg-muted)',
    }[tone] || 'var(--a-fg-muted)';

    const dot = p.dot === false ? '' :
      `<icon-ui name="circle-fill" data-trace-dot style="color:${color}"></icon-ui>`;

    const label = p.label != null ? String(p.label) : '';
    const value = p.value != null ? String(p.value) : '';
    const text = value ? `${value}${label ? ` ${label}` : ''}` : label;

    return `<span data-trace-pill>${dot}<span>${escapeText(text)}</span></span>`;
  }
}

function escapeText(s) {
  return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function escapeAttr(s) {
  return String(s).replace(/"/g, '&quot;');
}

customElements.define('agent-trace-ui', UIAgentTrace);
export { UIAgentTrace };
