"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 ListManager_exports = {};
__export(ListManager_exports, {
  ListManager: () => ListManager
});
module.exports = __toCommonJS(ListManager_exports);
var import_general = require("#general");
var import_model = require("#model");
var import_protocol = require("#protocol");
var import_types = require("#types");
var import_Instrumentation = require("../Instrumentation.js");
var import_Internal = require("../Internal.js");
var import_ManagedReference = require("../ManagedReference.js");
var import_PrimitiveManager = require("./PrimitiveManager.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
function ListManager(owner, schema) {
  const config = createConfig(owner, schema);
  return (list, session) => {
    if (!Array.isArray(list.value)) {
      throw new import_protocol.SchemaImplementationError(
        list.location,
        `Cannot manage ${typeof list.value} because it is not an array`
      );
    }
    return createProxy(config, list, session);
  };
}
function createConfig(owner, schema) {
  const entry = schema instanceof import_model.ValueModel ? schema.listEntry : void 0;
  if (entry === void 0) {
    throw new import_protocol.SchemaImplementationError((0, import_model.DataModelPath)(schema.path), "List schema has no entry definition");
  }
  const entryManager = owner.get(entry);
  const access = (0, import_protocol.AccessControl)(schema);
  return {
    schema,
    fabricScoped: schema.effectiveAccess.fabric === import_model.Access.Fabric.Scoped,
    fabricSensitive: schema.effectiveAccess.fabric === import_model.Access.Fabric.Sensitive,
    manageEntries: entryManager.manage !== import_PrimitiveManager.PrimitiveManager,
    manageEntry: entryManager.manage,
    validateEntry: entryManager.validate,
    authorizeRead: access.authorizeRead,
    authorizeWrite: access.authorizeWrite
  };
}
function createProxy(config, reference, session) {
  const { manageEntries, manageEntry, validateEntry, authorizeRead, authorizeWrite } = config;
  const readVal = () => reference.value ?? [];
  const writeVal = () => {
    if (reference.expired) {
      throw new import_protocol.ExpiredReferenceError(reference.location);
    }
    return reference.value;
  };
  let getListLength = () => readVal().length;
  let setListLength = (length) => {
    if (length > 65535) {
      throw new import_protocol.WriteError(reference.location, `Index ${length} is greater than allowed maximum of 65535`);
    }
    reference.change(() => writeVal().length = length);
  };
  let hasEntry = (index) => readVal()[index] !== void 0;
  let readEntry;
  let getIteratorFn = () => readVal()[Symbol.iterator];
  let ownKeys = () => Reflect.ownKeys(readVal());
  let getOwnPropertyDescriptor = (_target, key) => Reflect.getOwnPropertyDescriptor(readVal(), key);
  const sublocation = {
    ...reference.location,
    path: reference.location.path.at(-1)
  };
  if (manageEntries) {
    readEntry = (index) => {
      authorizeRead(session, reference.location);
      if (index < 0 || index >= readVal().length) {
        throw new import_protocol.ReadError(reference.location, `Index ${index} is out of bounds`);
      }
      if (index > 65535) {
        throw new import_protocol.ReadError(reference.location, `Index ${index} is greater than allowed maximum of 65535`);
      }
      const value = readVal()[index];
      if (value === void 0 || value === null) {
        return value;
      }
      let subref = reference.subrefs?.[index];
      if (subref === void 0) {
        subref = (0, import_ManagedReference.ManagedReference)(
          reference,
          "name",
          index,
          // For managed reference's purposes this is our "name"
          void 0,
          () => true,
          (val) => Array.isArray(val) ? [...val] : (0, import_general.isObject)(val) ? { ...val } : val,
          session
        );
        manageEntry(subref, session);
      }
      return subref.owner;
    };
  } else {
    readEntry = (index, location) => {
      authorizeRead(session, location);
      if (index < 0 || index > readVal().length) {
        throw new import_protocol.ReadError(location, `Index ${index} is out of bounds`);
      }
      return readVal()[index];
    };
  }
  let writeEntry = (index, value, location) => {
    authorizeWrite(session, location);
    if (index < 0 || index > readVal().length + 1) {
      throw new import_protocol.WriteError(location, `Index ${index} is out of bounds`);
    }
    if (index > 65535) {
      throw new import_protocol.ReadError(location, `Index ${index} is greater than allowed maximum of 65535`);
    }
    if (value && value[import_Internal.Internal.reference]) {
      value = value[import_Internal.Internal.reference].value;
    }
    reference.change(() => writeVal()[index] = value);
  };
  if (manageEntries && config.fabricScoped) {
    let mapScopedToActual2 = function(index, reading) {
      if (index < 0) {
        throw new (reading ? import_protocol.ReadError : import_protocol.WriteError)(reference.location, `Negative index ${index} unsupported`);
      }
      let nextPos = 0;
      for (let i = 0; i < readVal().length; i++) {
        const entry = readVal()[i];
        if (!(0, import_general.isObject)(entry)) {
          continue;
        }
        if ((0, import_protocol.hasLocalActor)(session) || !entry.fabricIndex || entry.fabricIndex === session.fabric) {
          if (nextPos === index) {
            return i;
          }
          nextPos++;
        }
      }
      if (reading) {
        throw new import_protocol.ReadError(reference.location, `Index ${index} extends beyond available entries`);
      }
      if (nextPos === index) {
        return readVal().length;
      }
      throw new import_protocol.WriteError(reference.location, `Index ${index} would leave gaps in fabric-filtered list`);
    };
    var mapScopedToActual = mapScopedToActual2;
    if ((0, import_protocol.hasRemoteActor)(session) && (session.fabricFiltered || config.fabricSensitive)) {
      const nextReadEntry = readEntry;
      hasEntry = (index) => {
        try {
          return nextReadEntry(mapScopedToActual2(index, true), reference.location) !== void 0;
        } catch (e) {
          return false;
        }
      };
      readEntry = (index, location) => {
        return nextReadEntry(mapScopedToActual2(index, true), location);
      };
      const nextWriteEntry = writeEntry;
      writeEntry = (index, value, location) => {
        if (value === void 0) {
          const valueIndex = mapScopedToActual2(index, false);
          writeVal().splice(valueIndex, 1);
        } else {
          if (!(0, import_general.isObject)(value)) {
            throw new import_protocol.WriteError(location, `Fabric scoped list value is not an object`, import_types.StatusCode.Failure);
          }
          value.fabricIndex ??= session.fabric;
          nextWriteEntry(mapScopedToActual2(index, false), value, location);
        }
      };
      getListLength = () => {
        let length = 0;
        for (let i = 0; i < readVal().length; i++) {
          const entry = readVal()[i];
          if ((0, import_general.isObject)(entry) && (!entry.fabricIndex || entry.fabricIndex === session.fabric)) {
            length++;
          }
        }
        return length;
      };
      setListLength = (length) => {
        const formerLength = getListLength();
        reference.change(() => {
          for (let i = formerLength - 1; i >= length; i--) {
            const entry = writeVal()[mapScopedToActual2(i, true)];
            if ((0, import_general.isObject)(entry) && (!entry.fabricIndex || entry.fabricIndex === session.fabric)) {
              writeVal().splice(mapScopedToActual2(i, false), 1);
            } else if (entry !== void 0) {
              throw new import_protocol.WriteError(
                reference.location,
                `Fabric scoped list value is not an object`,
                import_types.StatusCode.Failure
              );
            }
          }
        });
      };
      getIteratorFn = () => () => {
        const iterator = readVal()[Symbol.iterator]();
        return {
          ...iterator,
          next() {
            while (true) {
              const next = iterator.next();
              if (!next.done && (0, import_general.isObject)(next.value) && next.value.fabricIndex !== session.fabric) {
                continue;
              }
              return next;
            }
          },
          [Symbol.iterator]() {
            return this;
          }
        };
      };
      ownKeys = () => {
        const length = getListLength();
        const keys = Reflect.ownKeys(readVal()).filter((k) => {
          if (typeof k !== "string") {
            return true;
          }
          if (!k.match(/^\d+$/)) {
            return true;
          }
          if (Number.parseInt(k) < length) {
            return true;
          }
          return false;
        });
        return keys;
      };
      getOwnPropertyDescriptor = (_target, key) => {
        if (typeof key === "string" && key.match(/^\d+$/)) {
          key = Number.parseInt(key);
        }
        if (typeof key !== "number") {
          return Reflect.getOwnPropertyDescriptor(readVal(), key);
        }
        return Reflect.getOwnPropertyDescriptor(readVal(), mapScopedToActual2(key, true));
      };
    }
  }
  const target = [];
  const handlers = {
    get(_target, property, receiver) {
      if (typeof property === "string" && property.match(/^\d+/)) {
        sublocation.path.id = property;
        return readEntry(Number.parseInt(property), sublocation);
      }
      switch (property) {
        case "length":
          return getListLength();
        case Symbol.iterator:
          return getIteratorFn();
        case import_Internal.Internal.reference:
          return reference;
        case "toString":
          return function() {
            return (0, import_general.serialize)(this);
          };
        case Symbol.toStringTag:
          return void 0;
      }
      return Reflect.get(readVal(), property, receiver);
    },
    // On write we enter a transaction
    set(_target, property, newValue, receiver) {
      if (typeof property === "string" && property.match(/^\d+/)) {
        sublocation.path.id = property;
        validateEntry?.(newValue, session, sublocation);
        writeEntry(Number.parseInt(property), newValue, sublocation);
        return true;
      } else if (property === "length") {
        setListLength(newValue);
        return true;
      }
      return Reflect.set(writeVal(), property, newValue, receiver);
    },
    has(_target, property) {
      if (typeof property === "string" && property.match(/^\d+/)) {
        return hasEntry(Number.parseInt(property));
      }
      return Reflect.has(readVal(), property);
    },
    deleteProperty: (_target, property) => {
      if (typeof property === "string" && property.match(/^\d+/)) {
        sublocation.path.id = property;
        writeEntry(Number.parseInt(property), void 0, sublocation);
        return true;
      }
      return Reflect.deleteProperty(writeVal(), property);
    },
    ownKeys,
    getOwnPropertyDescriptor
  };
  const factory = import_Instrumentation.Instrumentation.instrumentList((handlers2, target2) => new Proxy(target2, handlers2));
  reference.owner = factory(handlers, target);
  return reference.owner;
}
//# sourceMappingURL=ListManager.js.map
