// src/lisp/primitives/mccarthy.ts
// McCarthy's Original 7 Primitives + eq
//
// These are the foundational operations from which all of LISP can be built.
// Reference: "Recursive Functions of Symbolic Expressions" (McCarthy, 1960)

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

export type PrimitiveHandler = (args: SExpr[], evaluate: (expr: SExpr) => Promise<unknown>) => Promise<unknown>;

export interface IPrimitiveDefinition {
  name: string;
  aliases?: string[];
  handler: PrimitiveHandler;
}

/**
 * QUOTE - Return the argument unevaluated
 * (quote x) → x
 * 'x → x
 */
export const quote: IPrimitiveDefinition = {
  name: 'quote',
  handler: async (args) => args[0],
};

/**
 * ATOM - Is this a primitive (not a list)?
 * (atom 'x) → true
 * (atom '(a b)) → false
 */
export const atom: IPrimitiveDefinition = {
  name: 'atom',
  aliases: ['atom?'],
  handler: async (args, evaluate) => {
    const val = await evaluate(args[0]);
    return !Array.isArray(val);
  },
};

/**
 * EQ - Are two atoms equal?
 * (eq 'a 'a) → true
 * (eq 'a 'b) → false
 */
export const eq: IPrimitiveDefinition = {
  name: 'eq',
  aliases: ['eq?'],
  handler: async (args, evaluate) => {
    const a = await evaluate(args[0]);
    const b = await evaluate(args[1]);
    return a === b;
  },
};

/**
 * CAR - First element of a list
 * (car '(a b c)) → a
 */
export const car: IPrimitiveDefinition = {
  name: 'car',
  aliases: ['first'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]);
    if (!Array.isArray(list) || list.length === 0) return null;
    return list[0];
  },
};

/**
 * CDR - Rest of a list (everything but first)
 * (cdr '(a b c)) → (b c)
 */
export const cdr: IPrimitiveDefinition = {
  name: 'cdr',
  aliases: ['rest'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]);
    if (!Array.isArray(list) || list.length === 0) return [];
    return list.slice(1);
  },
};

/**
 * CONS - Construct a list by prepending
 * (cons 'a '(b c)) → (a b c)
 */
export const cons: IPrimitiveDefinition = {
  name: 'cons',
  handler: async (args, evaluate) => {
    const head = await evaluate(args[0]);
    const tail = await evaluate(args[1]);
    if (!Array.isArray(tail)) return [head, tail];
    return [head, ...tail];
  },
};

/**
 * COND - Conditional expression
 * (cond ((test1) result1) ((test2) result2) (else default))
 */
export const cond: IPrimitiveDefinition = {
  name: 'cond',
  handler: async (args, evaluate) => {
    for (const clause of args) {
      const [test, result] = clause as SExpr[];
      if (test === 'else' || await evaluate(test)) {
        return await evaluate(result);
      }
    }
    return null;
  },
};

/**
 * List accessor shortcuts
 */
export const cadr: IPrimitiveDefinition = {
  name: 'cadr',
  aliases: ['second'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]) as unknown[];
    return Array.isArray(list) && list.length > 1 ? list[1] : null;
  },
};

export const caddr: IPrimitiveDefinition = {
  name: 'caddr',
  aliases: ['third'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]) as unknown[];
    return Array.isArray(list) && list.length > 2 ? list[2] : null;
  },
};

export const cadddr: IPrimitiveDefinition = {
  name: 'cadddr',
  aliases: ['fourth'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]) as unknown[];
    return Array.isArray(list) && list.length > 3 ? list[3] : null;
  },
};

/**
 * All McCarthy primitives
 */
export const mccarthyPrimitives: IPrimitiveDefinition[] = [
  quote,
  atom,
  eq,
  car,
  cdr,
  cons,
  cond,
  cadr,
  caddr,
  cadddr,
];
