/**
 * @license
 * Copyright 2025-2026 Open Home Foundation
 * SPDX-License-Identifier: Apache-2.0
 */
import { Observable } from "@matter/general";
import { Logger, Node } from "@matter/main";
import { AccessControlServer } from "@matter/node/behaviors/access-control";
import { WebRtcTransportRequestorBehavior } from "@matter/node/behaviors/web-rtc-transport-requestor";
import { assertRemoteActor, FabricAuthority, NodeSession } from "@matter/protocol";
import { Status, StatusResponseError } from "@matter/types";
import { AccessControl } from "@matter/types/clusters/access-control";
import { WebRtcTransportRequestor } from "@matter/types/clusters/web-rtc-transport-requestor";
const logger = Logger.get("WebRtcTransportRequestorServer");
class WebRtcTransportRequestorServer extends WebRtcTransportRequestorBehavior {
  upsertSession(session) {
    const enriched = {
      ...session,
      videoStreamId: session.videoStreams?.[0] ?? null,
      audioStreamId: session.audioStreams?.[0] ?? null
    };
    const sessions = this.state.currentSessions;
    const idx = sessions.findIndex((s) => s.id === session.id);
    if (idx === -1) {
      this.state.currentSessions = [...sessions, enriched];
    } else {
      this.state.currentSessions = sessions.map((s, i) => i === idx ? enriched : s);
    }
  }
  removeSession(id) {
    this.state.currentSessions = this.state.currentSessions.filter((s) => s.id !== id);
  }
  async offer(request) {
    logger.info(`incoming Offer webRtcSessionId=${request.webRtcSessionId} sdpLen=${request.sdp.length}`);
    const session = this.#findSessionStrict(request.webRtcSessionId);
    this.events.offer.emit(session, request);
  }
  async answer(request) {
    logger.info(`incoming Answer webRtcSessionId=${request.webRtcSessionId} sdpLen=${request.sdp.length}`);
    const session = this.#findSessionStrict(request.webRtcSessionId);
    this.events.answer.emit(session, request.sdp);
  }
  async iceCandidates(request) {
    logger.info(
      `incoming ICECandidates webRtcSessionId=${request.webRtcSessionId} count=${request.iceCandidates.length}`
    );
    if (request.iceCandidates.length === 0) {
      throw new StatusResponseError("ICE candidates list must not be empty", Status.InvalidCommand);
    }
    const session = this.#findSessionStrict(request.webRtcSessionId);
    this.events.iceCandidates.emit(session, request.iceCandidates);
  }
  async end(request) {
    logger.info(`incoming End webRtcSessionId=${request.webRtcSessionId} reason=${request.reason}`);
    const session = this.#findSessionStrict(request.webRtcSessionId);
    this.removeSession(request.webRtcSessionId);
    this.events.end.emit(session, request.reason);
  }
  async initialize() {
    const node = Node.forEndpoint(this.endpoint);
    logger.info(
      `initialized on endpoint=${this.endpoint.number} (id="${this.endpoint.id}") cluster=0x${WebRtcTransportRequestor.id.toString(16)}`
    );
    this.reactTo(node.lifecycle.online, this.#nodeOnline);
    if (node.lifecycle.isOnline) {
      await this.#nodeOnline();
    }
  }
  async #nodeOnline() {
    const fabricAuthority = this.env.get(FabricAuthority);
    const ownFabric = fabricAuthority.fabrics[0];
    if (!ownFabric) {
      fabricAuthority.fabricAdded.once(() => void this.#nodeOnline());
      return;
    }
    const node = Node.forEndpoint(this.endpoint);
    await node.act((agent) => agent.load(AccessControlServer));
    if (node.behaviors.has(AccessControlServer)) {
      if (!node.stateOf(AccessControlServer).acl.some(
        ({ fabricIndex, privilege, authMode, subjects, targets }) => fabricIndex === ownFabric.fabricIndex && privilege === AccessControl.AccessControlEntryPrivilege.Operate && authMode === AccessControl.AccessControlEntryAuthMode.Case && subjects?.length === 0 && targets?.length === 1 && targets[0].endpoint === this.endpoint.number && targets[0].cluster === WebRtcTransportRequestor.id
      )) {
        const acl = [
          ...node.stateOf(AccessControlServer).acl,
          {
            fabricIndex: ownFabric.fabricIndex,
            privilege: AccessControl.AccessControlEntryPrivilege.Operate,
            authMode: AccessControl.AccessControlEntryAuthMode.Case,
            subjects: [],
            targets: [{ endpoint: this.endpoint.number, cluster: WebRtcTransportRequestor.id }]
          }
        ];
        await node.setStateOf(AccessControlServer, { acl });
      }
    }
  }
  #findSessionStrict(id) {
    assertRemoteActor(this.context);
    NodeSession.assert(this.context.session);
    const peer = this.context.session.peerAddress;
    const session = this.state.currentSessions.find((s) => s.id === id);
    if (session === void 0 || session.fabricIndex !== peer.fabricIndex || session.peerNodeId !== peer.nodeId) {
      throw new StatusResponseError(`WebRTC session ${id} not found`, Status.NotFound);
    }
    return session;
  }
}
((WebRtcTransportRequestorServer2) => {
  class State extends WebRtcTransportRequestorBehavior.State {
    currentSessions = new Array();
  }
  WebRtcTransportRequestorServer2.State = State;
  class Events extends WebRtcTransportRequestorBehavior.Events {
    offer = Observable();
    answer = Observable();
    iceCandidates = Observable();
    end = Observable();
  }
  WebRtcTransportRequestorServer2.Events = Events;
})(WebRtcTransportRequestorServer || (WebRtcTransportRequestorServer = {}));
export {
  WebRtcTransportRequestorServer
};
//# sourceMappingURL=WebRtcTransportRequestorServer.js.map
