/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { FabricManager } from "#fabric/FabricManager.js";
import { AsyncObservable, Environmental, Logger, MatterFlowError } from "#general";
import { ExchangeManager } from "#protocol/ExchangeManager.js";
import { NodeSession } from "#session/NodeSession.js";
import { SessionManager } from "#session/SessionManager.js";
import {
  GeneralStatusCode,
  SECURE_CHANNEL_PROTOCOL_ID,
  SecureChannelStatusCode,
  SecureMessageType,
  StatusCode,
  StatusResponseError
} from "#types";
import { CaseServer } from "../session/case/CaseServer.js";
import { MaximumPasePairingErrorsReachedError } from "../session/pase/PaseServer.js";
import { ChannelStatusResponseError, SecureChannelMessenger } from "./SecureChannelMessenger.js";
import { SecureChannelStatusMessage } from "./SecureChannelStatusMessageSchema.js";
const logger = Logger.get("SecureChannelProtocol");
class StatusReportOnlySecureChannelProtocol {
  id = SECURE_CHANNEL_PROTOCOL_ID;
  // We need to check the message details to decide if ok or not, so we take them all
  requiresSecureSession = void 0;
  async onNewExchange(exchange, message) {
    const messageType = message.payloadHeader.messageType;
    switch (messageType) {
      case SecureMessageType.StatusReport:
        await this.handleInitialStatusReport(exchange, message);
        break;
      default:
        if (messageType !== SecureMessageType.StandaloneAck) {
          throw new StatusResponseError(
            `Unexpected initial message on secure channel protocol: ${messageType.toString(16)}`,
            StatusCode.InvalidAction
          );
        }
    }
  }
  async handleInitialStatusReport(exchange, message) {
    const {
      payloadHeader: { messageType },
      payload
    } = message;
    if (messageType !== SecureMessageType.StatusReport) {
      throw new MatterFlowError(
        `Unexpected message type on secure channel protocol, expected StatusReport: ${messageType.toString(
          16
        )}`
      );
    }
    const { generalStatus, protocolId, protocolStatus } = SecureChannelStatusMessage.decode(payload);
    if (generalStatus !== GeneralStatusCode.Success) {
      throw new ChannelStatusResponseError(
        `Received general error status (${protocolId})`,
        generalStatus,
        protocolStatus
      );
    }
    if (protocolStatus !== SecureChannelStatusCode.CloseSession) {
      throw new ChannelStatusResponseError(
        `Received general success status, but protocol status is not CloseSession`,
        generalStatus,
        protocolStatus
      );
    }
    const { session } = exchange;
    NodeSession.assert(session);
    logger.debug(exchange.via, "Closed by peer");
    await session.handlePeerClose();
  }
  async close() {
  }
}
class SecureChannelProtocol extends StatusReportOnlySecureChannelProtocol {
  #paseCommissioner;
  #caseCommissioner;
  #tooManyPaseErrors = AsyncObservable();
  constructor(sessions, fabrics) {
    super();
    this.#caseCommissioner = new CaseServer(sessions, fabrics);
  }
  static [Environmental.create](env) {
    const instance = new SecureChannelProtocol(env.get(SessionManager), env.get(FabricManager));
    env.get(ExchangeManager).addProtocolHandler(instance);
    env.set(SecureChannelProtocol, instance);
    return instance;
  }
  /**
   * Emitted when the active PASE session hits the maximum error threshold.
   */
  get tooManyPaseErrors() {
    return this.#tooManyPaseErrors;
  }
  setPaseCommissioner(paseServer) {
    this.#paseCommissioner = paseServer;
  }
  async removePaseCommissioner() {
    await this.#paseCommissioner?.close();
    this.#paseCommissioner = void 0;
  }
  async onNewExchange(exchange, message) {
    const messageType = message.payloadHeader.messageType;
    switch (messageType) {
      case SecureMessageType.PbkdfParamRequest:
        if (this.#paseCommissioner === void 0) {
          const messenger = new SecureChannelMessenger(exchange);
          await messenger.sendError(SecureChannelStatusCode.InvalidParam);
          await messenger.close();
          return;
        }
        try {
          await this.#paseCommissioner.onNewExchange(exchange);
        } catch (error) {
          MaximumPasePairingErrorsReachedError.accept(error);
          await this.#tooManyPaseErrors.emit();
        }
        break;
      case SecureMessageType.Sigma1:
        await this.#caseCommissioner.onNewExchange(exchange);
        break;
      default:
        await super.onNewExchange(exchange, message);
    }
  }
}
export {
  SecureChannelProtocol,
  StatusReportOnlySecureChannelProtocol
};
//# sourceMappingURL=SecureChannelProtocol.js.map
