// src/framework/shadowlisp/primitives/SlFilter.ts
//
// Vision 49: REAL filter primitive - NO JavaScript cheating
//
// <sl-filter predicate="is-red">
//   <sl-ref>cards</sl-ref>
// </sl-filter>
//
// The predicate is a ShadowLisp closure that returns truthy/falsy.
// This is REAL functional programming - the predicate is evaluated
// via applySlClosure for EACH element.

import type { SExpr } from '../../../lisp/SExpr';
import { SlMatrixElement } from '../SlMatrixElement';
import type { ISlClosure } from '../SlBootstrap';
import { isClosure } from '../SlBootstrap';
import { applySlClosure } from './SlLambda';

/**
 * SlFilter - REAL filter primitive using ShadowLisp predicates.
 *
 * @example
 * <sl-filter predicate="is-red">
 *   <sl-ref>cards</sl-ref>
 * </sl-filter>
 *
 * The predicate closure is looked up from the environment and applied
 * to each element. Only elements where predicate returns truthy are kept.
 */
export class SlFilter extends SlMatrixElement {
  /**
   * Get the predicate name to look up in environment.
   */
  get predicateName(): string {
    return this.getAttribute('predicate') ?? '';
  }

  /**
   * Evaluate: filter the list using REAL predicate closure.
   */
  async evalSelf(env: SExpr[]): Promise<SExpr> {
    // Get the list to filter (child element)
    const listChild = this.children[0];
    if (!listChild) {
      return [];
    }

    const list = await this.evalChild(listChild, env);
    if (!Array.isArray(list)) {
      this.warnKernel('[SlFilter] Child did not evaluate to array:', list);
      return [];
    }

    // Look up the predicate closure from environment
    const predicateName = this.predicateName;
    if (!predicateName) {
      this.warnKernel('[SlFilter] No predicate attribute specified');
      return list;
    }

    // Find predicate in environment
    let predicate: ISlClosure | null = null;
    for (const [name, value] of env as [string, SExpr][]) {
      if (name === predicateName) {
        if (isClosure(value)) {
          predicate = value;
        }
        break;
      }
    }

    if (!predicate) {
      this.warnKernel(`[SlFilter] Predicate '${predicateName}' not found in environment`);
      return list;
    }

    this.infoKernel(`[SlFilter] Filtering with REAL predicate '${predicateName}':`, predicate);

    // Filter using REAL closure application
    const result: SExpr[] = [];
    for (let i = 0; i < list.length; i++) {
      const item = list[i];
      // Apply predicate closure to item - THIS IS REAL, NOT JS!
      const keep = await applySlClosure(predicate, [item]);
      this.infoKernel(`[SlFilter] Predicate(item[${i}]) =>`, keep);

      if (keep !== false && keep !== null && keep !== undefined) {
        result.push(item);
      }
    }

    this.infoKernel(`[SlFilter] Filtered ${list.length} -> ${result.length} items`);
    return result;
  }

  toSExpr(): SExpr {
    return ['filter', this.predicateName,
      this.children[0] instanceof SlMatrixElement ? this.children[0].toSExpr() : null
    ];
  }
}

// Register
if (!customElements.get('sl-filter')) {
  customElements.define('sl-filter', SlFilter);
}
