// src/framework/shadowlisp/primitives/SlCond.ts
//
// Vision 49: Conditional element - IS a Matrix component
//
// John McCarthy (LISP creator, Turing Award 1971):
//   "Cond is the fundamental conditional. It evaluates clauses in order,
//    returning the result of the first whose test is true."
//
// <sl-cond>
//   <sl-clause><test1><result1></sl-clause>
//   <sl-clause><test2><result2></sl-clause>
//   <sl-clause><sl-true/><default></sl-clause>
// </sl-cond>

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

/**
 * SlCond - Conditional element (McCarthy primitive #7) that IS a Matrix component.
 *
 * Evaluates clauses in order. Returns the result of the first
 * clause whose test evaluates to true.
 *
 * @example
 * <sl-cond>
 *   <sl-clause>
 *     <sl-eq><sl-ref>x</sl-ref><sl-num>0</sl-num></sl-eq>
 *     <sl-str>zero</sl-str>
 *   </sl-clause>
 *   <sl-clause>
 *     <sl-true/>
 *     <sl-str>non-zero</sl-str>
 *   </sl-clause>
 * </sl-cond>
 */
export class SlCond extends SlMatrixElement {
  async evalSelf(env: SExpr[]): Promise<SExpr> {
    // Each child should be an <sl-clause> with [test, result]
    for (const clause of this.children) {
      if (clause.tagName.toLowerCase() !== 'sl-clause') {
        continue;
      }

      const [testEl, resultEl] = Array.from(clause.children);
      if (!testEl || !resultEl) {
        continue;
      }

      // Evaluate the test by calling its mount
      const testResult = await this.evalChild(testEl, env);

      // If truthy, evaluate and return the result
      if (testResult !== false && testResult !== null) {
        return this.evalChild(resultEl, env);
      }
    }

    // No clause matched
    return null;
  }

  toSExpr(): SExpr {
    const clauses: SExpr[] = [];
    for (const clause of this.children) {
      if (clause.tagName.toLowerCase() === 'sl-clause') {
        const [testEl, resultEl] = Array.from(clause.children);
        const test = (testEl instanceof SlMatrixElement) ? testEl.toSExpr() : null;
        const result = (resultEl instanceof SlMatrixElement) ? resultEl.toSExpr() : null;
        clauses.push([test, result]);
      }
    }
    return ['cond', ...clauses];
  }
}

if (!customElements.get('sl-cond')) {
  customElements.define('sl-cond', SlCond);
}
