/*!
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {TmplAstElement} from '@angular/compiler';
import {TcbOp} from './base';
import {TcbExpr} from './codegen';
import type {Context} from './context';
import type {Scope} from './scope';

/**
 * A `TcbOp` which creates an expression for a native DOM element (or web component) from a
 * `TmplAstElement`.
 *
 * Executing this operation returns a reference to the element variable.
 */
export class TcbElementOp extends TcbOp {
  constructor(
    private tcb: Context,
    private scope: Scope,
    private element: TmplAstElement,
  ) {
    super();
  }

  override get optional() {
    // The statement generated by this operation is only used for type-inference of the DOM
    // element's type and won't report diagnostics by itself, so the operation is marked as optional
    // to avoid generating statements for DOM elements that are never referenced.
    return true;
  }

  override execute(): TcbExpr {
    const id = this.tcb.allocateId();
    const idNode = new TcbExpr(id);
    idNode.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);

    // Add the declaration of the element using document.createElement.
    const initializer = new TcbExpr(`document.createElement("${this.element.name}")`);
    initializer.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);
    const stmt = new TcbExpr(`var ${idNode.print()} = ${initializer.print()}`);
    stmt.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);
    this.scope.addStatement(stmt);
    return idNode;
  }
}
