/**
 * @license
 * Copyright 2022-2024 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { AdministratorCommissioningServer } from "#behaviors/administrator-commissioning";
import { BasicInformationServer } from "#behaviors/basic-information";
import { AdministratorCommissioning } from "#clusters/administrator-commissioning";
import { GeneralCommissioning } from "#clusters/general-commissioning";
import { Logger, MatterFlowError } from "#general";
import { assertSecureSession, DeviceCommissioner, FabricManager, SessionManager } from "#protocol";
import { GeneralCommissioningBehavior } from "./GeneralCommissioningBehavior.js";
import { ServerNodeFailsafeContext } from "./ServerNodeFailsafeContext.js";
const SuccessResponse = { errorCode: GeneralCommissioning.CommissioningError.Ok, debugText: "" };
const logger = Logger.get("GeneralCommissioningClusterHandler");
class GeneralCommissioningServer extends GeneralCommissioningBehavior {
  initialize() {
    const bci = this.state.basicCommissioningInfo;
    if (bci.failSafeExpiryLengthSeconds === void 0) {
      bci.failSafeExpiryLengthSeconds = 60;
    }
    if (bci.maxCumulativeFailsafeSeconds === void 0) {
      bci.maxCumulativeFailsafeSeconds = 900;
    }
    this.state.breadcrumb = 0;
  }
  async armFailSafe({ breadcrumb, expiryLengthSeconds }) {
    assertSecureSession(this.session, "armFailSafe can only be called on a secure session");
    const commissioner = this.env.get(DeviceCommissioner);
    try {
      if (!commissioner.isFailsafeArmed && this.agent.get(AdministratorCommissioningServer).state.windowStatus !== AdministratorCommissioning.CommissioningWindowStatus.WindowNotOpen && !this.session.isPase) {
        throw new MatterFlowError("Failed to arm failsafe using CASE while commissioning window is opened.");
      }
      if (commissioner.isFailsafeArmed) {
        await commissioner.failsafeContext.extend(this.session.fabric, expiryLengthSeconds);
      } else {
        if (expiryLengthSeconds === 0) return SuccessResponse;
        await commissioner.beginTimed(
          new ServerNodeFailsafeContext(this.endpoint, {
            fabrics: this.env.get(FabricManager),
            sessions: this.env.get(SessionManager),
            expiryLengthSeconds,
            maxCumulativeFailsafeSeconds: this.state.basicCommissioningInfo.maxCumulativeFailsafeSeconds,
            associatedFabric: this.session.fabric
          })
        );
      }
      if (commissioner.isFailsafeArmed) {
        this.state.breadcrumb = breadcrumb;
      }
    } catch (error) {
      MatterFlowError.accept(error);
      logger.debug(`Error while arming failSafe timer`, error);
      return {
        errorCode: GeneralCommissioning.CommissioningError.BusyWithOtherAdmin,
        debugText: error.message
      };
    }
    return SuccessResponse;
  }
  async setRegulatoryConfig({
    breadcrumb,
    newRegulatoryConfig,
    countryCode
  }) {
    const locationCapabilityValue = this.state.locationCapability;
    const basicInformation = this.agent.get(BasicInformationServer);
    const currentLocationCountryCode = basicInformation.state.location;
    if (currentLocationCountryCode !== countryCode) {
      if (this.state.allowCountryCodeChange === false && countryCode !== "XX") {
        return {
          errorCode: GeneralCommissioning.CommissioningError.ValueOutsideRange,
          debugText: `Country code change not allowed: ${countryCode}`
        };
      }
      if (this.state.countryCodeWhitelist !== void 0 && !this.state.countryCodeWhitelist.includes(countryCode)) {
        return {
          errorCode: GeneralCommissioning.CommissioningError.ValueOutsideRange,
          debugText: `Country code change not allowed: ${countryCode}`
        };
      }
      if (countryCode !== "XX") {
        basicInformation.state.location = countryCode;
      }
    }
    let validValues;
    switch (locationCapabilityValue) {
      case GeneralCommissioning.RegulatoryLocationType.Outdoor:
        validValues = [GeneralCommissioning.RegulatoryLocationType.Outdoor];
        break;
      case GeneralCommissioning.RegulatoryLocationType.Indoor:
        validValues = [GeneralCommissioning.RegulatoryLocationType.Indoor];
        break;
      case GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor:
        validValues = [
          GeneralCommissioning.RegulatoryLocationType.Indoor,
          GeneralCommissioning.RegulatoryLocationType.Outdoor,
          GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor
        ];
        break;
      default:
        return {
          errorCode: GeneralCommissioning.CommissioningError.ValueOutsideRange,
          debugText: `Invalid regulatory location: ${newRegulatoryConfig === GeneralCommissioning.RegulatoryLocationType.Indoor ? "Indoor" : "Outdoor"}`
        };
    }
    if (!validValues.includes(newRegulatoryConfig)) {
      return {
        errorCode: GeneralCommissioning.CommissioningError.ValueOutsideRange,
        debugText: `Invalid regulatory location: ${newRegulatoryConfig === GeneralCommissioning.RegulatoryLocationType.Indoor ? "Indoor" : "Outdoor"}`
      };
    }
    this.asAdmin(() => {
      this.state.regulatoryConfig = newRegulatoryConfig;
    });
    this.state.breadcrumb = breadcrumb;
    return SuccessResponse;
  }
  async commissioningComplete() {
    if (this.session.isPase) {
      return {
        errorCode: GeneralCommissioning.CommissioningError.InvalidAuthentication,
        debugText: "Command not executed over CASE session."
      };
    }
    const fabric = this.session.associatedFabric;
    const commissioner = this.env.get(DeviceCommissioner);
    if (!commissioner.isFailsafeArmed) {
      return { errorCode: GeneralCommissioning.CommissioningError.NoFailSafe, debugText: "FailSafe not armed." };
    }
    const failsafeContext = commissioner.failsafeContext;
    assertSecureSession(this.session, "commissioningComplete can only be called on a secure session");
    const timedFabric = failsafeContext.associatedFabric?.fabricIndex;
    if (fabric.fabricIndex !== timedFabric) {
      return {
        errorCode: GeneralCommissioning.CommissioningError.InvalidAuthentication,
        debugText: `Associated fabric ${fabric.fabricIndex} does not match the one from the failsafe context ${timedFabric}.`
      };
    }
    await failsafeContext.completeCommission();
    this.state.breadcrumb = BigInt(0);
    logger.info(`Commissioning completed on fabric #${fabric.fabricId} as node #${fabric.nodeId}.`);
    return SuccessResponse;
  }
}
((GeneralCommissioningServer2) => {
  class State extends GeneralCommissioningBehavior.State {
    /**
     * Set to false to prevent the controller from changing the country code during commissioning.
     */
    allowCountryCodeChange = true;
    // Default true if not set
    /**
     * Set to an array of two-letter country codes to limit the countries the controller may assign.
     */
    countryCodeWhitelist = void 0;
  }
  GeneralCommissioningServer2.State = State;
})(GeneralCommissioningServer || (GeneralCommissioningServer = {}));
export {
  GeneralCommissioningServer
};
//# sourceMappingURL=GeneralCommissioningServer.js.map
