"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("@matter/general");
var import_model = require("@matter/model");
var import_protocol = require("@matter/protocol");
var import_types = require("@matter/types");
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(new 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
  };
}
const assertWriteOkAlways = () => true;
const cloneEntry = (val) => Array.isArray(val) ? [...val] : (0, import_general.isObject)(val) ? { ...val } : val;
const inspectCustom = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
function listToString() {
  return (0, import_general.serialize)(this);
}
function inspectList() {
  return [...this];
}
class ListProxyHandler {
  reference;
  session;
  config;
  #sublocation;
  constructor(config, reference, session) {
    this.reference = reference;
    this.session = session;
    this.config = config;
    this.#sublocation = {
      ...reference.location,
      path: reference.location.path.at(-1)
    };
  }
  readVal() {
    return this.reference.value ?? [];
  }
  writeVal() {
    if (this.reference.expired) {
      throw new import_protocol.ExpiredReferenceError(this.reference.location);
    }
    return this.reference.value;
  }
  getListLength() {
    return this.readVal().length;
  }
  setListLength(length) {
    if (length > 65535) {
      throw new import_protocol.WriteError(this.reference.location, `Index ${length} is greater than allowed maximum of 65535`);
    }
    this.reference.change(() => this.writeVal().length = length);
  }
  hasEntry(index) {
    return this.readVal()[index] !== void 0;
  }
  readEntry(index, location) {
    if (this.config.manageEntries) {
      this.config.authorizeRead(this.session, this.reference.location);
      if (index < 0 || index >= this.readVal().length) {
        throw new import_protocol.ReadError(this.reference.location, `Index ${index} is out of bounds`);
      }
      if (index > 65535) {
        throw new import_protocol.ReadError(this.reference.location, `Index ${index} is greater than allowed maximum of 65535`);
      }
      const value = this.readVal()[index];
      if (value === void 0 || value === null) {
        return value;
      }
      let subref = this.reference.subrefs?.[index];
      if (subref === void 0) {
        subref = new import_ManagedReference.ManagedReference(
          this.reference,
          "name",
          index,
          void 0,
          assertWriteOkAlways,
          cloneEntry,
          this.session
        );
        this.config.manageEntry(subref, this.session);
      }
      return subref.owner;
    } else {
      this.config.authorizeRead(this.session, location);
      if (index < 0 || index > this.readVal().length) {
        throw new import_protocol.ReadError(location, `Index ${index} is out of bounds`);
      }
      return this.readVal()[index];
    }
  }
  writeEntry(index, value, location) {
    this.config.authorizeWrite(this.session, location);
    if (index < 0 || index > this.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`);
    }
    value = import_Internal.Internal.unmanage(value);
    this.reference.change(() => this.writeVal()[index] = value);
  }
  getIteratorFn() {
    return this.readVal()[Symbol.iterator];
  }
  get(_target, property, receiver) {
    if (typeof property === "string" && property.match(/^\d+/)) {
      this.#sublocation.path.id = property;
      return this.readEntry(Number.parseInt(property), this.#sublocation);
    }
    switch (property) {
      case "length":
        return this.getListLength();
      case Symbol.iterator:
        return this.getIteratorFn();
      case import_Internal.Internal.reference:
        return this.reference;
      case "toString":
        return listToString;
      case inspectCustom:
        return inspectList;
      case Symbol.toStringTag:
        return void 0;
    }
    return Reflect.get(this.readVal(), property, receiver);
  }
  set(_target, property, newValue, receiver) {
    if (typeof property === "string" && property.match(/^\d+/)) {
      this.#sublocation.path.id = property;
      this.config.validateEntry?.(newValue, this.session, this.#sublocation);
      this.writeEntry(Number.parseInt(property), newValue, this.#sublocation);
      return true;
    } else if (property === "length") {
      this.setListLength(newValue);
      return true;
    }
    return Reflect.set(this.writeVal(), property, newValue, receiver);
  }
  has(_target, property) {
    if (typeof property === "string" && property.match(/^\d+/)) {
      return this.hasEntry(Number.parseInt(property));
    }
    return Reflect.has(this.readVal(), property);
  }
  deleteProperty(_target, property) {
    if (typeof property === "string" && property.match(/^\d+/)) {
      this.#sublocation.path.id = property;
      this.writeEntry(Number.parseInt(property), void 0, this.#sublocation);
      return true;
    }
    return Reflect.deleteProperty(this.writeVal(), property);
  }
  ownKeys() {
    return Reflect.ownKeys(this.readVal());
  }
  getOwnPropertyDescriptor(_target, key) {
    return Reflect.getOwnPropertyDescriptor(this.readVal(), key);
  }
}
class FabricFilteredListProxyHandler extends ListProxyHandler {
  #mapScopedToActual(index, reading) {
    if (index < 0) {
      throw new (reading ? import_protocol.ReadError : import_protocol.WriteError)(
        this.reference.location,
        `Negative index ${index} unsupported`
      );
    }
    let nextPos = 0;
    for (let i = 0; i < this.readVal().length; i++) {
      const entry = this.readVal()[i];
      if (!(0, import_general.isObject)(entry)) {
        continue;
      }
      if ((0, import_protocol.hasLocalActor)(this.session) || !entry.fabricIndex || entry.fabricIndex === this.session.fabric) {
        if (nextPos === index) {
          return i;
        }
        nextPos++;
      }
    }
    if (reading) {
      throw new import_protocol.ReadError(this.reference.location, `Index ${index} extends beyond available entries`);
    }
    if (nextPos === index) {
      return this.readVal().length;
    }
    throw new import_protocol.WriteError(this.reference.location, `Index ${index} would leave gaps in fabric-filtered list`);
  }
  hasEntry(index) {
    try {
      return super.readEntry(this.#mapScopedToActual(index, true), this.reference.location) !== void 0;
    } catch (e) {
      return false;
    }
  }
  readEntry(index, location) {
    return super.readEntry(this.#mapScopedToActual(index, true), location);
  }
  writeEntry(index, value, location) {
    if (value === void 0) {
      const valueIndex = this.#mapScopedToActual(index, false);
      this.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 ??= this.session.fabric;
      super.writeEntry(this.#mapScopedToActual(index, false), value, location);
    }
  }
  getListLength() {
    let length = 0;
    for (let i = 0; i < this.readVal().length; i++) {
      const entry = this.readVal()[i];
      if ((0, import_general.isObject)(entry) && (!entry.fabricIndex || entry.fabricIndex === this.session.fabric)) {
        length++;
      }
    }
    return length;
  }
  setListLength(length) {
    const formerLength = this.getListLength();
    this.reference.change(() => {
      for (let i = formerLength - 1; i >= length; i--) {
        const entry = this.writeVal()[this.#mapScopedToActual(i, true)];
        if ((0, import_general.isObject)(entry) && (!entry.fabricIndex || entry.fabricIndex === this.session.fabric)) {
          this.writeVal().splice(this.#mapScopedToActual(i, false), 1);
        } else if (entry !== void 0) {
          throw new import_protocol.WriteError(
            this.reference.location,
            `Fabric scoped list value is not an object`,
            import_types.StatusCode.Failure
          );
        }
      }
    });
  }
  getIteratorFn() {
    const fabric = this.session.fabric;
    const readVal = () => this.readVal();
    return (() => {
      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 !== fabric) {
              continue;
            }
            return next;
          }
        },
        [Symbol.iterator]() {
          return this;
        }
      };
    });
  }
  ownKeys() {
    const length = this.getListLength();
    return Reflect.ownKeys(this.readVal()).filter((k) => {
      if (typeof k !== "string") {
        return true;
      }
      if (!k.match(/^\d+$/)) {
        return true;
      }
      if (Number.parseInt(k) < length) {
        return true;
      }
      return false;
    });
  }
  getOwnPropertyDescriptor(_target, key) {
    if (typeof key === "string" && key.match(/^\d+$/)) {
      key = Number.parseInt(key);
    }
    if (typeof key !== "number") {
      return Reflect.getOwnPropertyDescriptor(this.readVal(), key);
    }
    return Reflect.getOwnPropertyDescriptor(this.readVal(), this.#mapScopedToActual(key, true));
  }
}
function createProxy(config, reference, session) {
  const isFabricFiltered = config.manageEntries && config.fabricScoped && (0, import_protocol.hasRemoteActor)(session) && (session.fabricFiltered || config.fabricSensitive);
  const handler = isFabricFiltered ? new FabricFilteredListProxyHandler(config, reference, session) : new ListProxyHandler(config, reference, session);
  reference.owner = new Proxy([], handler);
  return reference.owner;
}
//# sourceMappingURL=ListManager.js.map
