// src/framework/shadowlisp/SlAtom.ts
//
// Vision 48: ShadowLisp Atomic Value Element
//
// John McCarthy (LISP creator, Turing Award 1971):
//   "Atoms are the primitives - symbols, numbers, strings, booleans, nil.
//    Everything else is built from cons cells (forms)."
//
// <sl-atom> represents atomic (non-list) values in the DOM AST.

import type { SExpr } from '../../lisp/SExpr';

const SlAtomElementBase = HTMLElement;

/**
 * Atom kinds supported by ShadowLisp.
 */
export type AtomKind = 'sym' | 'num' | 'str' | 'bool' | 'nil';

/**
 * SlAtom - Atomic value custom element.
 *
 * Represents symbols, numbers, strings, booleans, and nil in the DOM.
 * The DOM IS the AST - no parsing needed.
 *
 * @example
 * <sl-atom kind="sym">user-name</sl-atom>     // Symbol
 * <sl-atom kind="num">42</sl-atom>            // Number
 * <sl-atom kind="str">Hello, World!</sl-atom> // String
 * <sl-atom kind="bool">true</sl-atom>         // Boolean
 * <sl-atom kind="nil"/>                       // Nil/null
 */
export class SlAtom extends SlAtomElementBase {
  static observedAttributes = ['kind'];

  constructor() {
    super();
    // No shadow DOM needed - atoms are simple
  }

  /**
   * Get the atom kind.
   * Default is 'sym' (symbol).
   */
  get kind(): AtomKind {
    const k = this.getAttribute('kind');
    if (k === 'num' || k === 'str' || k === 'bool' || k === 'nil') {
      return k;
    }
    return 'sym';
  }

  /**
   * Set the atom kind.
   */
  set kind(value: AtomKind) {
    this.setAttribute('kind', value);
  }

  /**
   * Get the atom's value, parsed according to kind.
   */
  get value(): string | number | boolean | null {
    const text = this.textContent?.trim() ?? '';

    switch (this.kind) {
      case 'num':
        return parseFloat(text) || 0;
      case 'bool':
        return text === 'true' || text === '#t' || text === 't';
      case 'nil':
        return null;
      case 'str':
        return text;
      case 'sym':
      default:
        return text;
    }
  }

  /**
   * Set the atom's value.
   */
  set value(val: string | number | boolean | null) {
    if (val === null) {
      this.kind = 'nil';
      this.textContent = '';
    } else if (typeof val === 'boolean') {
      this.kind = 'bool';
      this.textContent = val ? 'true' : 'false';
    } else if (typeof val === 'number') {
      this.kind = 'num';
      this.textContent = String(val);
    } else {
      // Default to string for symbols and strings
      this.textContent = String(val);
    }
  }

  /**
   * Convert this atom to S-expression format.
   *
   * Guy Steele (Scheme co-designer):
   *   "The beauty is that atoms ARE their S-expression representation.
   *    No transformation needed - just extract the value."
   *
   * NOTE: String literals (kind="str") are wrapped in quotes so evaluators
   * can distinguish them from symbols (kind="sym") which require lookup.
   */
  toSExpr(): SExpr {
    const text = this.textContent?.trim() ?? '';

    switch (this.kind) {
      case 'num':
        return parseFloat(text) || 0;
      case 'bool':
        return text === 'true' || text === '#t' || text === 't';
      case 'nil':
        return null;
      case 'str':
        // Wrap in quotes so evaluator knows it's a literal string
        return `"${text}"`;
      case 'sym':
      default:
        return text;
    }
  }

  /**
   * Create an SlAtom from an S-expression value.
   */
  static fromSExpr(value: SExpr): SlAtom {
    const atom = document.createElement('sl-atom') as SlAtom;

    if (value === null) {
      atom.kind = 'nil';
    } else if (typeof value === 'boolean') {
      atom.kind = 'bool';
      atom.textContent = value ? 'true' : 'false';
    } else if (typeof value === 'number') {
      atom.kind = 'num';
      atom.textContent = String(value);
    } else if (typeof value === 'string') {
      // Heuristic: strings starting with uppercase or containing spaces are strings
      // Otherwise treat as symbols
      if (value.includes(' ') || /^[A-Z]/.test(value) || value.includes('"')) {
        atom.kind = 'str';
      } else {
        atom.kind = 'sym';
      }
      atom.textContent = value;
    }

    return atom;
  }

  attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {
    if (name === 'kind') {
      // Could trigger re-render or validation
      this.dispatchEvent(new CustomEvent('sl-kind-changed', {
        bubbles: true,
        detail: { kind: this.kind }
      }));
    }
  }
}

// Define the custom element
if (!customElements.get('sl-atom')) {
  customElements.define('sl-atom', SlAtom);
}
