"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 IllegalFeatureCombinations_exports = {};
__export(IllegalFeatureCombinations_exports, {
  IllegalFeatureCombinations: () => IllegalFeatureCombinations
});
module.exports = __toCommonJS(IllegalFeatureCombinations_exports);
var import_general = require("@matter/general");
var import_aspects = require("../../aspects/index.js");
var import_FeatureBitmap = require("./FeatureBitmap.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
function IllegalFeatureCombinations(cluster) {
  const illegal = [];
  const choices = {};
  function add(flags) {
    if (!illegal.some((e) => (0, import_general.isDeepEqual)(e, flags))) {
      illegal.push(flags);
    }
  }
  for (const f of cluster.features) {
    addFeatureNode(f, f.conformance.ast, add, choices);
  }
  let requiresFeatures = false;
  for (const choice of Object.values(choices)) {
    if (choice.exclusive) {
      for (const f1 of choice.features) {
        for (const f2 of choice.features) {
          if (f1 !== f2) {
            add({ [f1]: true, [f2]: true });
          }
        }
      }
    }
    const flags = (0, import_FeatureBitmap.FeatureBitmap)();
    for (const f of choice.features) {
      flags[f] = false;
    }
    add(flags);
    requiresFeatures = true;
  }
  return { illegal, requiresFeatures };
}
function addFeatureNode(feature, node, add, choices) {
  switch (node.type) {
    case import_aspects.Conformance.Special.Desc:
    case import_aspects.Conformance.Special.Empty:
    case import_aspects.Conformance.Flag.Optional:
    case import_aspects.Conformance.Flag.Provisional:
      break;
    case import_aspects.Conformance.Flag.Mandatory:
      add({ [feature.name]: false });
      break;
    case import_aspects.Conformance.Flag.Deprecated:
    case import_aspects.Conformance.Flag.Disallowed:
      add({ [feature.name]: true });
      break;
    case import_aspects.Conformance.Special.Otherwise:
      const rules = node.param;
      const entryExclusions = Array();
      let optionalIfIndex;
      for (let i = 0; i < rules.length; i++) {
        if (rules[i].type === import_aspects.Conformance.Special.OptionalIf) {
          if (optionalIfIndex !== void 0) {
            unsupported();
          }
          optionalIfIndex = i;
        }
        const thisEntryExclusions = [];
        entryExclusions.push(thisEntryExclusions);
        addFeatureNode(feature, rules[i], (flags) => thisEntryExclusions.push(flags), choices);
      }
      if (optionalIfIndex !== void 0) {
        const negations = {};
        for (let i = 0; i < rules.length; i++) {
          if (i === optionalIfIndex) {
            continue;
          }
          for (const entry of entryExclusions[i]) {
            for (const name in entry) {
              if (negations[name] !== void 0) {
                unsupported();
              }
              negations[name] = !entry[name];
            }
          }
        }
        entryExclusions[optionalIfIndex] = entryExclusions[optionalIfIndex].map((exclusions) => ({
          ...negations,
          ...exclusions
        }));
      }
      for (const ee of entryExclusions) {
        ee.forEach(add);
      }
      break;
    case import_aspects.Conformance.Special.Choice:
      if (node.param.num > 1) {
        unsupported();
      }
      const choice = choices[node.param.name];
      if (choice) {
        choice.features.push(feature.name);
      } else {
        choices[node.param.name] = choices[node.param.name] = {
          exclusive: !node.param.orMore,
          features: [feature.name]
        };
      }
      break;
    case import_aspects.Conformance.Special.Name:
      add({ [node.param]: true, [feature.name]: false });
      break;
    case import_aspects.Conformance.Special.OptionalIf:
      switch (node.param.type) {
        case import_aspects.Conformance.AND:
        case import_aspects.Conformance.Special.Name:
          addDependencyRequirement(feature.name, node.param);
          break;
        case import_aspects.Conformance.OR: {
          const flags = (0, import_FeatureBitmap.FeatureBitmap)({ [feature.name]: true });
          addExclusivityRequirement(flags, node.param);
          add(flags);
          break;
        }
        case import_aspects.Conformance.Operator.NOT: {
          add({ [feature.name]: true, [extractName(node.param.param)]: true });
          break;
        }
        default:
          unsupported();
      }
      break;
    case import_aspects.Conformance.Operator.AND: {
      const lhsFeatures = extractDisjunctFeatures(node.param.lhs);
      const rhsFeature = extractFeatureFlag(node.param.rhs);
      for (const lhsFeature in lhsFeatures) {
        add({
          feature: false,
          [lhsFeature]: lhsFeatures[lhsFeature],
          ...rhsFeature
        });
      }
      break;
    }
    case import_aspects.Conformance.Operator.OR: {
      const features = extractDisjunctFeatures(node);
      add(Object.fromEntries(Object.entries(features).map((k, v) => [k, !v])));
      break;
    }
    default:
      unsupported();
  }
  function unsupported() {
    throw new import_general.InternalError(`New rule required to support ${feature.path} conformance "${feature.conformance}"`);
  }
  function extractName(node2) {
    if (node2.type === import_aspects.Conformance.Special.Name) {
      return node2.param;
    }
    unsupported();
  }
  function extractFeatureFlag(node2) {
    switch (node2.type) {
      case import_aspects.Conformance.Special.Name:
        return { [node2.param]: true };
      case import_aspects.Conformance.Operator.NOT:
        return { [extractName(node2.param)]: false };
      default:
        unsupported();
    }
  }
  function addExclusivityRequirement(flags, node2) {
    switch (node2.type) {
      case import_aspects.Conformance.OR:
        addExclusivityRequirement(flags, node2.param.lhs);
        addExclusivityRequirement(flags, node2.param.rhs);
        break;
      default:
        Object.assign(flags, extractFeatureFlag(node2));
        break;
    }
  }
  function addDependencyRequirement(feature2, node2) {
    switch (node2.type) {
      case import_aspects.Conformance.Special.Name:
        add({ [feature2]: true, [node2.param]: false });
        break;
      case import_aspects.Conformance.AND:
        addDependencyRequirement(feature2, node2.param.lhs);
        addDependencyRequirement(feature2, node2.param.rhs);
        break;
      case import_aspects.Conformance.OR:
        if (node2.param.lhs.type === import_aspects.Conformance.Special.Name && node2.param.rhs.type === import_aspects.Conformance.Special.Name) {
          add({ [feature2]: true, [node2.param.lhs.param]: false, [node2.param.rhs.param]: false });
        }
        break;
      case import_aspects.Conformance.Operator.NOT:
        if (node2.param.type === import_aspects.Conformance.Special.Name) {
          add({ [feature2]: true, [node2.param.param]: true });
        }
        break;
      default:
        unsupported();
    }
  }
  function extractDisjunctFeatures(node2) {
    const result = {};
    function extract(node3, invert = false) {
      switch (node3.type) {
        case import_aspects.Conformance.Special.Name:
          result[node3.param] = !invert;
          break;
        case import_aspects.Conformance.Operator.OR:
          extract(node3.param.lhs, invert);
          extract(node3.param.rhs, invert);
          break;
        case import_aspects.Conformance.Operator.NOT:
          extract(node3.param, !invert);
          break;
        default:
          unsupported();
      }
    }
    extract(node2);
    return result;
  }
}
//# sourceMappingURL=IllegalFeatureCombinations.js.map
