// src/framework/shadowlisp/primitives/SlGetAttr.ts
//
// Vision 49: REAL attribute accessor - NO JavaScript cheating
//
// <sl-get-attr name="data-color">
//   <sl-ref>card</sl-ref>
// </sl-get-attr>
//
// Returns the attribute value from a DOM element.

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

/**
 * SlGetAttr - Get attribute from DOM element.
 *
 * @example
 * <sl-get-attr name="data-color">
 *   <sl-ref>card</sl-ref>
 * </sl-get-attr>
 */
export class SlGetAttr extends SlMatrixElement {
  get attrName(): string {
    return this.getAttribute('name') ?? '';
  }

  async evalSelf(env: SExpr[]): Promise<SExpr> {
    const child = this.children[0];
    if (!child) {
      this.warnKernel('[SlGetAttr] No child element');
      return null;
    }

    const element = await this.evalChild(child, env);

    if (!(element instanceof HTMLElement)) {
      this.warnKernel('[SlGetAttr] Child did not evaluate to HTMLElement:', element);
      return null;
    }

    const attrName = this.attrName;
    if (!attrName) {
      this.warnKernel('[SlGetAttr] No name attribute specified');
      return null;
    }

    const value = element.getAttribute(attrName);
    this.infoKernel(`[SlGetAttr] ${attrName} => "${value}"`);
    return value;
  }

  toSExpr(): SExpr {
    const child = this.children[0];
    return ['get-attr', this.attrName,
      child instanceof SlMatrixElement ? child.toSExpr() : null
    ];
  }
}

/**
 * SlClassName - Get class name from DOM element.
 *
 * @example
 * <sl-class-name><sl-ref>element</sl-ref></sl-class-name>
 */
export class SlClassName extends SlMatrixElement {
  async evalSelf(env: SExpr[]): Promise<SExpr> {
    const child = this.children[0];
    if (!child) return null;

    const element = await this.evalChild(child, env);
    if (!(element instanceof HTMLElement)) return null;

    return element.className;
  }

  toSExpr(): SExpr {
    const child = this.children[0];
    return ['class-name', child instanceof SlMatrixElement ? child.toSExpr() : null];
  }
}

/**
 * SlHasClass - Check if element has a class.
 *
 * @example
 * <sl-has-class name="red"><sl-ref>element</sl-ref></sl-has-class>
 */
export class SlHasClass extends SlMatrixElement {
  get className(): string {
    return this.getAttribute('name') ?? '';
  }

  async evalSelf(env: SExpr[]): Promise<SExpr> {
    const child = this.children[0];
    if (!child) return false;

    const element = await this.evalChild(child, env);
    if (!(element instanceof HTMLElement)) return false;

    const result = element.classList.contains(this.className);
    this.infoKernel(`[SlHasClass] has-class "${this.className}" => ${result}`);
    return result;
  }

  toSExpr(): SExpr {
    const child = this.children[0];
    return ['has-class', this.className,
      child instanceof SlMatrixElement ? child.toSExpr() : null
    ];
  }
}

// Register
if (!customElements.get('sl-get-attr')) {
  customElements.define('sl-get-attr', SlGetAttr);
}
if (!customElements.get('sl-class-name')) {
  customElements.define('sl-class-name', SlClassName);
}
if (!customElements.get('sl-has-class')) {
  customElements.define('sl-has-class', SlHasClass);
}
