"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 ServiceAreaServer_exports = {};
__export(ServiceAreaServer_exports, {
  ServiceAreaBaseServer: () => ServiceAreaBaseServer,
  ServiceAreaServer: () => ServiceAreaServer
});
module.exports = __toCommonJS(ServiceAreaServer_exports);
var import_service_area = require("#clusters/service-area");
var import_general = require("#general");
var import_types = require("#types");
var import_ServiceAreaBehavior = require("./ServiceAreaBehavior.js");
/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const ServiceAreaBase = import_ServiceAreaBehavior.ServiceAreaBehavior.with(import_service_area.ServiceArea.Feature.Maps, import_service_area.ServiceArea.Feature.ProgressReporting);
class ServiceAreaBaseServer extends ServiceAreaBase {
  initialize() {
    this.#assertSupportedAreas(this.state.supportedAreas);
    this.reactTo(this.events.supportedAreas$Changing, this.#assertSupportedAreas);
    this.#assertSupportedMaps(this.state.supportedMaps);
    this.reactTo(this.events.supportedMaps$Changing, this.#assertSupportedMaps);
    this.#assertSelectedAreas(this.state.selectedAreas);
    this.reactTo(this.events.selectedAreas$Changing, this.#assertSelectedAreas);
    if (this.state.currentArea !== void 0) {
      this.#assertCurrentArea(this.state.currentArea);
      this.maybeReactTo(this.events.currentArea$Changing, this.#assertCurrentArea);
    }
    if (this.state.progress !== void 0) {
      this.#assertProgress(this.state.progress);
      this.reactTo(this.events.progress$Changing, this.#assertProgress);
    }
    if (this.state.currentArea !== void 0 && this.state.estimatedEndTime !== void 0) {
      if (this.state.currentArea === null) {
        this.state.estimatedEndTime = null;
      }
      if (this.events.estimatedEndTime$Changed !== void 0) {
        this.events.estimatedEndTime$Changed.quiet.shouldEmit = (newValue, oldValue) => {
          return oldValue === null || oldValue === 0 || newValue === null || newValue === 0 || newValue < oldValue ? "now" : true;
        };
      }
    }
  }
  #assertSupportedMaps(maps) {
    if (maps.length === 0) {
      return;
    }
    const mapIds = /* @__PURE__ */ new Set();
    const mapNames = /* @__PURE__ */ new Set();
    for (const { mapId, name } of maps) {
      if (mapIds.has(mapId)) {
        throw new import_types.ValidationError(`MapID ${mapId} is not unique`);
      }
      if (mapNames.has(name)) {
        throw new import_types.ValidationError(`MapName "${name}" is not unique`);
      }
      mapIds.add(mapId);
      mapNames.add(name);
    }
  }
  #assertSupportedAreas(areas) {
    const areaIds = /* @__PURE__ */ new Set();
    if (areas.length > 0) {
      for (const { areaId, areaInfo } of areas) {
        if (areaIds.has(areaId)) {
          throw new import_types.ValidationError(`AreaID ${areaId} is not unique`);
        }
        const { locationInfo, landmarkInfo } = areaInfo;
        if (locationInfo === null && landmarkInfo === null) {
          throw new import_types.ValidationError(`Area ${areaId} has no location or landmark info`);
        }
        if (locationInfo !== null) {
          const { locationName, floorNumber, areaType } = locationInfo;
          if (locationName === "" && floorNumber === null && areaType === null && landmarkInfo === null) {
            throw new import_types.ValidationError(`Area ${areaId} has no location info`);
          }
        }
        areaIds.add(areaId);
      }
      const mapIds = /* @__PURE__ */ new Set();
      for (let i = 0; i < areas.length; i++) {
        const { areaId, mapId, areaInfo } = areas[i];
        mapIds.add(mapId);
        for (let j = i + 1; j < areas.length; j++) {
          const otherArea = areas[j];
          if (otherArea.mapId !== mapId) {
            continue;
          }
          if ((0, import_general.isDeepEqual)(areaInfo, otherArea.areaInfo)) {
            throw new import_types.ValidationError(
              `Areas must have a unique AreaInfo field, but area ${areaId} and area ${otherArea.areaId} are equal`
            );
          }
        }
      }
      if (this.state.supportedMaps !== void 0 && this.state.supportedMaps.length > 0) {
        if (mapIds.has(null)) {
          throw new import_types.ValidationError(`Areas must not have a null mapId when supportedMaps is defined`);
        }
      } else {
        if (!mapIds.has(null) || mapIds.size > 1) {
          throw new import_types.ValidationError(`Areas must have a null mapId when supportedMaps is empty`);
        }
      }
    }
  }
  #assertSelectedAreas(areas) {
    const selectedAreaIds = /* @__PURE__ */ new Set();
    for (const areaId of areas) {
      if (!this.state.supportedAreas.some((area) => area.areaId === areaId)) {
        throw new import_types.ValidationError(`AreaID ${areaId} is not in the supported areas list`);
      }
      if (selectedAreaIds.has(areaId)) {
        throw new import_types.ValidationError(`AreaID ${areaId} is not unique`);
      }
      selectedAreaIds.add(areaId);
    }
  }
  #assertCurrentArea(areaId) {
    if (areaId === null) {
      if (this.state.estimatedEndTime !== void 0) {
        this.state.estimatedEndTime = null;
      }
      return;
    }
    if (!this.state.supportedAreas.some((area) => area.areaId === areaId)) {
      throw new import_types.ValidationError(`AreaID ${areaId} is not in the supported areas list`);
    }
  }
  #assertProgress(progress) {
    const areaIds = /* @__PURE__ */ new Set();
    for (const area of progress) {
      if (areaIds.has(area.areaId)) {
        throw new import_types.ValidationError(`AreaID ${area.areaId} is not unique`);
      }
      areaIds.add(area.areaId);
      if (!this.state.supportedAreas.some((supportedArea) => supportedArea.areaId === area.areaId)) {
        throw new import_types.ValidationError(`AreaID ${area.areaId} is not in the supported areas list`);
      }
    }
  }
  /**
   * This command is used to select a set of device areas, where the device is to operate.
   * On receipt of this command the device shall respond with a SelectAreasResponse command.
   *
   * The default implementation wil check the areaId as defined by the specification and internally calls
   * `assertSelectServiceArea`, which can be overridden to implement custom logic.
   * When a new list of areas is selected, the device shall clear the progress list and set the status of all areas to
   * Pending.
   */
  selectAreas({ newAreas }) {
    const { result, validatedAreas } = this.assertSelectServiceArea({ newAreas });
    if (result.status === import_service_area.ServiceArea.SelectAreasStatus.Success && validatedAreas !== void 0) {
      this.state.selectedAreas = validatedAreas;
      if (this.state.progress !== void 0 && validatedAreas.length > 0) {
        const progress = new Array();
        for (const area of validatedAreas) {
          progress.push({
            areaId: area,
            status: import_service_area.ServiceArea.OperationalStatus.Pending
          });
        }
        this.state.progress = progress;
      }
    }
    return result;
  }
  assertSelectServiceArea({ newAreas }) {
    const selectedAreaIds = /* @__PURE__ */ new Set();
    for (const areaId of newAreas) {
      if (!this.state.supportedAreas.some((area) => area.areaId === areaId)) {
        return {
          result: {
            status: import_service_area.ServiceArea.SelectAreasStatus.UnsupportedArea,
            statusText: `AreaID ${areaId} is not in the supported areas list`
          }
        };
      }
      selectedAreaIds.add(areaId);
    }
    const validatedAreas = Array.from(selectedAreaIds.values());
    return {
      result: {
        status: import_service_area.ServiceArea.SelectAreasStatus.Success,
        statusText: ""
      },
      validatedAreas
    };
  }
  assertSkipServiceArea({ skippedArea }) {
    if (this.state.selectedAreas.length === 0) {
      return {
        status: import_service_area.ServiceArea.SkipAreaStatus.InvalidAreaList,
        statusText: ""
      };
    }
    if (!this.state.selectedAreas.some((area) => area === skippedArea)) {
      return {
        status: import_service_area.ServiceArea.SkipAreaStatus.InvalidSkippedArea,
        statusText: `AreaID ${skippedArea} is not in the selected areas list`
      };
    }
    return {
      status: import_service_area.ServiceArea.SkipAreaStatus.Success,
      statusText: ""
    };
  }
  removeSupportedAreasEntry(areaId) {
    const supportedAreas = this.state.supportedAreas;
    if (supportedAreas === void 0 || supportedAreas.length === 0) {
      return;
    }
    this.state.selectedAreas = (0, import_general.deepCopy)(this.state.selectedAreas.filter((area) => area !== areaId));
    if (this.state.currentArea === areaId) {
      this.state.currentArea = null;
    }
    if (this.state.progress !== void 0) {
      this.state.progress = (0, import_general.deepCopy)(this.state.progress.filter((area) => area.areaId !== areaId));
    }
    this.state.supportedAreas = (0, import_general.deepCopy)(supportedAreas.filter((area) => area.areaId !== areaId));
  }
  /**
   * Convenience helper method to remove a map from the supported maps list.
   * The logic will also sync the SupportedAreas list with this removal.
   */
  removeSupportedMapsEntry(mapId) {
    const supportedMaps = this.state.supportedMaps;
    if (supportedMaps === void 0 || supportedMaps.length === 0) {
      return;
    }
    const mapToRemove = supportedMaps.find((map) => map.mapId === mapId);
    if (mapToRemove !== void 0) {
      const affectedArea = this.state.supportedAreas.find((area) => area.mapId === mapToRemove.mapId);
      if (affectedArea !== void 0) {
        this.removeSupportedAreasEntry(affectedArea.areaId);
      }
      this.state.supportedMaps = (0, import_general.deepCopy)(supportedMaps.filter((map) => map.mapId !== mapToRemove.mapId));
    }
  }
}
((ServiceAreaBaseServer2) => {
})(ServiceAreaBaseServer || (ServiceAreaBaseServer = {}));
class ServiceAreaServer extends ServiceAreaBaseServer.with() {
}
//# sourceMappingURL=ServiceAreaServer.js.map
