/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { camelize, GeneratedClass, isObject } from "@matter/general";
import { DataModelPath, FeatureMap } from "@matter/model";
import { ConstraintError, PhantomReferenceError, SchemaImplementationError } from "@matter/protocol";
import { assertBoolean, assertNumber } from "../../validation/assertions.js";
import { Instrumentation } from "../Instrumentation.js";
import { Internal } from "../Internal.js";
const SESSION = /* @__PURE__ */ Symbol("options");
function BitmapManager(owner, schema) {
  const instanceDescriptors = {};
  const byteSize = schema.metabase?.byteSize;
  if (byteSize === void 0) {
    throw new SchemaImplementationError(new DataModelPath(schema.path), `Base bitmap type has no byteSize defined`);
  }
  const maxBit = byteSize * 8;
  for (const member of owner.membersOf(schema)) {
    let name;
    if (schema.id === FeatureMap.id) {
      name = camelize(member.title ?? member.name);
    } else {
      name = member.propertyName;
    }
    const descriptor = configureProperty(name, maxBit, member);
    instanceDescriptors[name] = descriptor;
  }
  const Wrapper = GeneratedClass({
    name: schema.name,
    initialize(ref, session) {
      if (!isObject(ref.value)) {
        throw new SchemaImplementationError(
          ref.location,
          `Cannot manage ${typeof ref.value} because it is not a bitmap object`
        );
      }
      Object.defineProperties(this, {
        [Internal.reference]: {
          value: ref
        },
        [SESSION]: {
          value: session
        }
      });
      Object.defineProperties(this, instanceDescriptors);
    }
  });
  Instrumentation.instrumentStruct(Wrapper);
  return (reference, session) => {
    reference.owner = new Wrapper(reference, session);
    return reference.owner;
  };
}
function configureProperty(name, maxBit, schema) {
  const constraint = schema.effectiveConstraint;
  let startBit, stopBit;
  if (typeof constraint.value === "number") {
    startBit = constraint.value;
    stopBit = startBit + 1;
  } else if (typeof constraint.min === "number" && typeof constraint.max === "number") {
    startBit = constraint.min;
    stopBit = constraint.max + 1;
    if (startBit > stopBit) {
      const temp = startBit;
      startBit = stopBit;
      stopBit = temp;
    }
  } else {
    throw new SchemaImplementationError(new DataModelPath(schema.path), `Bitfield is not properly constrained`);
  }
  if (stopBit > maxBit) {
    throw new SchemaImplementationError(
      new DataModelPath(schema.path),
      `Bitfield range end ${stopBit} is too large for a ${maxBit}-bit bitmap`
    );
  }
  const max = 1 << stopBit - startBit;
  if (max === 2) {
    return {
      enumerable: true,
      get() {
        const bits = this[Internal.reference].value;
        if (bits === void 0) {
          throw new PhantomReferenceError(this[Internal.reference].location);
        }
        return !!bits[name];
      },
      set(value) {
        const ref = this[Internal.reference];
        if (value !== void 0) {
          assertBoolean(value, ref.location.path);
        }
        ref.change(() => {
          const bits = ref.value;
          if (bits === void 0) {
            throw new PhantomReferenceError(this[Internal.reference].location);
          }
          bits[name] = !!value;
        });
      }
    };
  }
  return {
    enumerable: true,
    get() {
      const bits = this[Internal.reference].value;
      if (bits === void 0) {
        throw new PhantomReferenceError(this[Internal.reference].location);
      }
      return bits[name];
    },
    set(value) {
      const ref = this[Internal.reference];
      if (value !== void 0) {
        assertNumber(value, ref.location.path);
        if (value >= max) {
          throw new ConstraintError(
            schema,
            this[Internal.reference].location,
            `Value ${value} is too large for bitfield`
          );
        } else if (value < 0) {
          throw new ConstraintError(
            schema,
            this[Internal.reference].location,
            `Illegal negative value ${value} for bitfield`
          );
        }
      }
      ref.change(() => {
        const bits = ref.value;
        if (bits === void 0) {
          throw new PhantomReferenceError(this[Internal.reference].location);
        }
        bits[name] = value ? value : 0;
      });
    }
  };
}
export {
  BitmapManager
};
//# sourceMappingURL=BitmapManager.js.map
