"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 ValueValidator_exports = {};
__export(ValueValidator_exports, {
  ValueValidator: () => ValueValidator
});
module.exports = __toCommonJS(ValueValidator_exports);
var import_aspects = require("../../aspects/index.js");
var import_common = require("../../common/index.js");
var import_models = require("../../models/index.js");
var import_ModelValidator = require("./ModelValidator.js");
var import_ValidationExceptions = require("./ValidationExceptions.js");
/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class ValueValidator extends import_ModelValidator.ModelValidator {
  validate() {
    this.validateProperty({ name: "type", type: "string" });
    this.validateProperty({ name: "byteSize", type: "number" });
    this.validateProperty({ name: "constraint", type: import_aspects.Constraint });
    this.validateProperty({ name: "conformance", type: import_aspects.Conformance });
    this.validateProperty({ name: "access", type: import_aspects.Access });
    this.validateProperty({ name: "quality", type: import_aspects.Quality });
    this.validateProperty({ name: "metatype", type: import_common.Metatype });
    this.validateAspect("conformance");
    this.model.conformance.validateReferences(this, (name) => {
      if (name.match(/^[A-Z0-9_$]+$/)) {
        const cluster = this.model.owner(import_models.ClusterModel);
        return !!cluster?.features.find((f) => f.name === name);
      }
      for (let model = this.model.parent; model; model = model.parent) {
        if (model.member(name) !== void 0) {
          return true;
        }
      }
      return false;
    });
    this.validateAspect("constraint");
    this.validateAspect("access");
    this.validateAspect("quality");
    this.validateType();
    this.validateEntries();
    super.validate();
  }
  validateAspect(name) {
    const aspect = this.model[name];
    if (aspect?.errors) {
      aspect.errors.forEach((e) => this.model.error(e.code, `${e.source}: ${e.message}`));
    }
  }
  validateType() {
    if (this.model.effectiveType === void 0) {
      if (this.model.metatype) {
        return;
      }
      if (this.model.isDeprecated || this.model.isDisallowed) {
        return;
      }
      this.error("NO_TYPE", "No type information");
      return;
    }
    const base = this.model.base;
    if (base === void 0) {
      return;
    }
    const metabase = this.model.metabase;
    if (metabase === void 0) {
      this.error("METATYPE_UNKNOWN", `No metatype for ${this.model.type}`);
      return;
    }
    const metatype = metabase.metatype;
    if (metatype === void 0) {
      this.error("METATYPE_MISSING", `Metabase ${metabase.name} has no metatype`);
      return;
    }
    let defaultValue = this.model.default;
    if (defaultValue === void 0) {
      return;
    }
    if (this.validateSpecialDefault(metatype, defaultValue)) {
      return;
    }
    if (metatype === import_common.Metatype.string && defaultValue === "empty") {
      delete this.model.default;
      return;
    }
    const cast = import_common.FieldValue.cast(metatype, defaultValue);
    if (typeof defaultValue === "string") {
      let referenced = this.model?.member(defaultValue);
      if (referenced === void 0) {
        referenced = this.model.owner(import_models.ClusterModel)?.member(defaultValue);
      }
      if (referenced instanceof import_models.ValueModel && referenced.effectiveType === this.model.effectiveType) {
        this.model.default = import_common.FieldValue.Reference(referenced.name);
        return;
      }
    }
    if (cast === import_common.FieldValue.Invalid) {
      this.error("INVALID_VALUE", `Value "${defaultValue}" is not a ${metatype}`);
      return;
    }
    defaultValue = cast;
    if (metatype === import_common.Metatype.enum) {
      if (typeof defaultValue === "string") {
        let member = this.model.member(defaultValue);
        if (!member) {
          member = this.model.member(
            (model) => model.name.toLowerCase() === defaultValue.toLowerCase()
          );
        }
        if (member && member.effectiveId !== void 0) {
          defaultValue = member.effectiveId;
        } else {
          this.error("INVALID_ENTRY", `"${defaultValue}" is not in ${metatype} ${this.model.type}`);
        }
      }
    }
    this.model.default = defaultValue;
  }
  validateEntries() {
    const metatype = this.model.type === void 0 ? void 0 : import_models.Globals[this.model.type]?.metatype;
    switch (metatype) {
      case import_common.Metatype.object:
        if (!this.model.children.length) {
          this.error("CHILDLESS_STRUCT", `struct element with no children`);
        }
        break;
      case import_common.Metatype.enum:
      case import_common.Metatype.bitmap:
        const base = this.model.base;
        if (!base || !base.isSeed || !base.name.startsWith("enum") || this.model.parent?.name === "semtag") {
          break;
        }
        if (!this.model.members.length && !import_ValidationExceptions.ValidationExceptions.AllowedEmptyEnums.has(this.model.path)) {
          this.error(`CHILDLESS_${metatype.toUpperCase()}`, `${this.model.type} with no children`);
        }
        if (metatype == import_common.Metatype.enum) {
          this.validateEnumKeys();
        } else {
          this.validateBitFields();
        }
        break;
      case import_common.Metatype.array:
        if (!this.model.children.length) {
          this.error("UNTYPED_ARRAY", `array element with no entry type`);
        } else if (this.model.children.length > 1) {
          this.error("OVERLY_TYPED_ARRAY", `array element with multiple entry types`);
        }
        break;
    }
  }
  validateEnumKeys() {
    const ids = /* @__PURE__ */ new Set();
    const names = /* @__PURE__ */ new Set();
    for (const c of this.model.children) {
      if (c.id) {
        if (ids.has(c.id)) {
          this.error(
            "DUPLICATE_ENUM_ID",
            `${this.model.type} ID 0x${c.id.toString(16)} appears more than once`
          );
        } else {
          ids.add(c.id);
        }
      }
      if (names.has(c.name)) {
        this.error("DUPLICATE_ENUM_NAME", `${this.model.type} name "${c.name}" appears more than once`);
      }
    }
  }
  validateBitFields() {
    const ranges = Array();
    for (const c of this.model.children) {
      let min, max;
      if (typeof c.constraint.value === "number") {
        min = c.constraint.value;
        max = c.constraint.value + 1;
      } else {
        min = c.constraint.min;
        max = c.constraint.max;
        if (typeof min !== "number" || typeof max !== "number" || min < 0 || min > max) {
          this.error(
            "UNCONSTRAINED_BIT_RANGE",
            `${this.model.type} bit field "${c.name}" is not properly constrained`
          );
          continue;
        }
      }
      for (const r of ranges) {
        if (min < r.max && max > r.min) {
          this.error(
            "OVERLAPPING_BIT_RANGE",
            `${this.model.type} bit fields "${r.name}" and "${c.name}" overlap`
          );
        }
      }
      ranges.push({ name: c.name, min, max });
    }
  }
  validateSpecialDefault(metatype, def) {
    if (typeof def === "object" && import_common.FieldValue.is(def, import_common.FieldValue.reference)) {
      const reference = def.name;
      const other = this.model.parent?.member(reference);
      if (!other) {
        this.error("MEMBER_UNKNOWN", `Default value references unknown property ${reference}`);
      }
      return true;
    }
    if (typeof def === "string") {
      const other = this.model.parent?.member(def);
      if (other) {
        this.model.default = import_common.FieldValue.Reference(other.name);
        return true;
      }
    }
    if (metatype === import_common.Metatype.bitmap && Array.isArray(def)) {
      for (const value of def) {
        if (typeof value !== "string" && typeof value !== "number") {
          this.error("INVALID_BIT_FLAG", `Default bit flag ${def} is not a string or number`);
          continue;
        }
        if (!this.model.member(value)) {
          this.error("UNRESOLVED_BIT_FLAG", `Default bit flag ${def} is not a valid bit value`);
        }
      }
      return true;
    }
  }
}
//# sourceMappingURL=ValueValidator.js.map
