"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var NameDependentElements_exports = {};
__export(NameDependentElements_exports, {
  NameDependentElements: () => NameDependentElements
});
module.exports = __toCommonJS(NameDependentElements_exports);
var import_general = require("@matter/general");
var import_model = require("@matter/model");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const { Applicability, Flag, Operator, Special } = import_model.Conformance;
class NameDependentElements {
  /**
   * Elements whose conformance is runtime-conditional (e.g. comparisons, `Desc`) but doesn't reference sibling
   * elements.  Presence is based solely on whether the element is implemented since we can't evaluate the actual
   * condition at behavior construction time.  Also used as resolved deps by {@link interdependents}.
   */
  conditionals = /* @__PURE__ */ new Map();
  /**
   * Elements with sibling element references — needs dependency graph resolution.
   */
  interdependents = /* @__PURE__ */ new Map();
  #featureContext;
  constructor(featureContext) {
    this.#featureContext = featureContext;
  }
  /**
   * Add an element whose conformance evaluated as {@link Conformance.Applicability.Conditional}.
   *
   * Classifies the conformance AST and sorts the element into either `conditionals` (resolved immediately) or
   * `interdependents` (needs graph resolution).
   */
  add(model, elementType, isImplemented) {
    const ast = model.effectiveConformance.ast;
    const result = classify(ast, this.#featureContext, model);
    if (result === "conditional") {
      this.conditionals.set(model.name, { model, elementType, isImplemented, presence: isImplemented });
    } else {
      const { dependencies, fallback } = extractInterdependencies(ast, this.#featureContext, model);
      this.interdependents.set(model.name, { model, elementType, isImplemented, dependencies, fallback });
    }
  }
}
function classify(ast, featureContext, model) {
  switch (ast.type) {
    case Special.Name:
      if (featureContext.definedFeatures.has(ast.param)) {
        return "conditional";
      }
      return isCommandOrEventName(ast.param, model) ? "interdependent" : "conditional";
    case Special.Otherwise:
      for (const clause of ast.param) {
        if (classify(clause, featureContext, model) === "interdependent") {
          return "interdependent";
        }
      }
      return "conditional";
    case Operator.OR:
      if (classify(ast.param.lhs, featureContext, model) === "interdependent") return "interdependent";
      if (classify(ast.param.rhs, featureContext, model) === "interdependent") return "interdependent";
      return "conditional";
    case Operator.AND:
      if (classify(ast.param.lhs, featureContext, model) === "interdependent") return "interdependent";
      if (classify(ast.param.rhs, featureContext, model) === "interdependent") return "interdependent";
      return "conditional";
    case Special.OptionalIf:
      return classify(ast.param, featureContext, model);
    case Special.Choice:
      return classify(ast.param.expr, featureContext, model);
    case Operator.NOT:
    case Operator.EQ:
    case Operator.NE:
    case Operator.GT:
    case Operator.LT:
    case Operator.GTE:
    case Operator.LTE:
    case Special.Desc:
    case Special.Empty:
    case Special.Revision:
    case Flag.Mandatory:
    case Flag.Optional:
    case Flag.Disallowed:
    case Flag.Deprecated:
    case Flag.Provisional:
      return "conditional";
    default:
      throw new import_general.InternalError(`Unsupported conformance AST type "${ast.type}" for element classification`);
  }
}
function extractInterdependencies(ast, featureContext, model) {
  switch (ast.type) {
    case Special.Name:
      return { dependencies: [ast.param], fallback: Applicability.None };
    case Operator.OR:
      return { dependencies: flattenOrNames(ast, featureContext, model), fallback: Applicability.None };
    case Special.Otherwise:
      return extractOtherwiseInterdependencies(ast.param, featureContext, model);
    case Special.OptionalIf: {
      const inner = extractInterdependencies(ast.param, featureContext, model);
      if (inner.fallback === Applicability.None) {
        inner.fallback = Applicability.Optional;
      }
      return inner;
    }
    case Special.Choice:
      return extractInterdependencies(ast.param.expr, featureContext, model);
    default:
      throw new import_general.InternalError(`Unsupported top-level interdependent conformance pattern "${ast.type}"`);
  }
}
function extractOtherwiseInterdependencies(clauses, featureContext, model) {
  const dependencies = [];
  let fallback = Applicability.None;
  for (const clause of clauses) {
    switch (clause.type) {
      case Special.Name:
        if (featureContext.definedFeatures.has(clause.param)) {
        } else {
          dependencies.push(clause.param);
        }
        break;
      case Operator.OR:
        dependencies.push(...flattenOrNames(clause, featureContext, model));
        break;
      case Flag.Optional:
      case Special.OptionalIf:
        fallback = Applicability.Optional;
        break;
      case Flag.Mandatory:
        fallback = Applicability.Mandatory;
        break;
      case Flag.Disallowed:
      case Flag.Deprecated:
      case Flag.Provisional:
        fallback = Applicability.None;
        break;
      case Special.Choice: {
        const inner = extractInterdependencies(clause.param.expr, featureContext, model);
        dependencies.push(...inner.dependencies);
        break;
      }
      default:
        throw new import_general.InternalError(
          `Unsupported otherwise clause type "${clause.type}" in interdependent conformance`
        );
    }
  }
  return { dependencies, fallback };
}
function flattenOrNames(ast, featureContext, model) {
  const names = [];
  const stack = [ast];
  while (stack.length > 0) {
    const node = stack.pop();
    if (node.type === Operator.OR) {
      stack.push(node.param.lhs, node.param.rhs);
    } else if (node.type === Special.Name) {
      if (!featureContext.definedFeatures.has(node.param) && isCommandOrEventName(node.param, model)) {
        names.push(node.param);
      }
    } else {
      throw new import_general.InternalError(
        `Unexpected node type "${node.type}" in OR tree of interdependent conformance \u2014 expected element names`
      );
    }
  }
  return names;
}
function isCommandOrEventName(name, model) {
  return model.parent?.resolve(name, { tags: [import_model.ElementTag.Command, import_model.ElementTag.Event] }) !== void 0;
}
//# sourceMappingURL=NameDependentElements.js.map
