// src/lisp/components/SchemeEval.ts
// SchemeEval MatrixActor - S-Expression Syntax Evaluator
//
// Parses Scheme/LISP syntax like (+ 1 2 3) and delegates to LispEval.
// This provides the human-friendly S-expression interface.
//
// Reference: Vision/15-LISP-ON-PROTOCOL.md

import { MatrixActor } from '../../core/MatrixActor';
import { RequestReply } from '../../engine/remoting/RequestReply';
import type { SExpr } from '../SExpr';
import { parseSExpr, parseForEval, toSExpr, prettySExpr, SCHEME_EXAMPLES } from '../core/SExprParser';

/**
 * SchemeEval - Evaluates S-expression syntax
 *
 * This component provides the human-readable S-expression interface:
 *   (define (fact n) (if (< n 2) 1 (* n (fact (- n 1)))))
 *   (fact 5)
 *   → 120
 *
 * It parses the Scheme syntax to JSON wire format and delegates to LispEval.
 *
 * Mount: {namespace}.scheme
 *
 * @example
 * await callComponent('flowpad.scheme', 'eval', {
 *   source: '(+ 1 2 (* 3 4))'
 * })
 * // → 15
 */
export class SchemeEval extends MatrixActor {
  static accepts = {
    eval: { source: 'string' },
    parse: { source: 'string' },
    format: { expr: 'any', pretty: 'boolean?' },
    examples: {},
  };

  static emits = {
    evaluated: { source: 'string', parsed: 'any', result: 'any', durationMs: 'number' },
    parsed: { source: 'string', result: 'any' },
    parseError: { source: 'string', error: 'string' },
  };

  protected async onBootstrap(): Promise<void> {
    // eslint-disable-next-line no-console -- standalone lisp runtime, no actor context
    console.log(`[SchemeEval] Initialized at ${this._context?.mount}`);
  }

  /**
   * Evaluate Scheme source code
   */
  async onEval(params: { source: string }): Promise<unknown> {
    const startTime = performance.now();
    const { source } = params;

    if (!source || typeof source !== 'string') {
      throw new Error('SchemeEval.eval requires a "source" string parameter');
    }

    try {
      // Parse S-expression to JSON wire format
      const parsed = parseForEval(source);
      // eslint-disable-next-line no-console -- standalone lisp runtime, no actor context
      console.log('[SchemeEval] Parsed:', JSON.stringify(parsed));

      // Derive sibling LispEval mount (supports root and nested mount shapes).
      const lispMount = this._deriveLispSiblingMount(this._context?.mount ?? '');

      // Delegate to LispEval via network call
      const result = await RequestReply.execute(
        this._context!,
        lispMount,
        'eval',
        { expr: parsed },
        { timeoutMs: 5000 }
      );

      const durationMs = performance.now() - startTime;
      this.emit('evaluated', { source, parsed, result, durationMs });
      return result;
    } catch (err: unknown) {
      const error = err instanceof Error ? err.message : String(err);
      this.emit('parseError', { source, error });
      throw err;
    }
  }

  /**
   * Parse Scheme source without evaluating
   */
  async onParse(params: { source: string }): Promise<SExpr> {
    const { source } = params;

    try {
      const result = parseSExpr(source);
      this.emit('parsed', { source, result });
      return result;
    } catch (err: unknown) {
      const error = err instanceof Error ? err.message : String(err);
      this.emit('parseError', { source, error });
      throw err;
    }
  }

  /**
   * Format JSON wire format as S-expression string
   */
  async onFormat(params: { expr: SExpr; pretty?: boolean }): Promise<string> {
    const { expr, pretty } = params;
    return pretty ? prettySExpr(expr) : toSExpr(expr);
  }

  /**
   * Get available example programs
   */
  async onExamples(): Promise<Record<string, string>> {
    return SCHEME_EXAMPLES;
  }

  private _deriveLispSiblingMount(mount: string): string {
    const normalized = mount.trim();
    if (normalized.length === 0) return 'lisp';
    if (normalized.endsWith('.scheme')) {
      return `${normalized.slice(0, -'.scheme'.length)}.lisp`;
    }
    if (normalized === 'scheme') return 'lisp';
    if (normalized.endsWith('/scheme')) {
      return `${normalized.slice(0, -'/scheme'.length)}/lisp`;
    }
    return normalized;
  }
}
