const require_rolldown_runtime = require('../../../../../_virtual/rolldown_runtime.js');
const require_decorateMetadata = require('../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateMetadata.js');
const require_decorate = require('../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js');
const require_DidCommOutboundMessageContext = require('../../models/DidCommOutboundMessageContext.js');
require('../../models/index.js');
const require_index$1 = require('../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/cjs/index.js');
const require_DidCommModuleConfig = require('../../DidCommModuleConfig.js');
const require_DidCommTransportEventTypes = require('../../transport/DidCommTransportEventTypes.js');
require('../../transport/index.js');
const require_decorateParam = require('../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.js');
const require_index$3 = require('../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/cjs/operators/index.js');
const require_DidCommConnectionService = require('../connections/services/DidCommConnectionService.js');
const require_DidCommMessageSender = require('../../DidCommMessageSender.js');
const require_DidCommConnectionMetadataTypes = require('../connections/repository/DidCommConnectionMetadataTypes.js');
const require_DidCommRoutingEvents = require('./DidCommRoutingEvents.js');
const require_DidCommKeylistUpdateMessage = require('./messages/DidCommKeylistUpdateMessage.js');
require('./messages/index.js');
const require_DidCommMediationState = require('./models/DidCommMediationState.js');
const require_DidCommMediatorPickupStrategy = require('./DidCommMediatorPickupStrategy.js');
const require_DidCommMediationRepository = require('./repository/DidCommMediationRepository.js');
const require_DidCommMediationRecipientService = require('./services/DidCommMediationRecipientService.js');
require('../connections/services/index.js');
const require_DidCommRoutingService = require('./services/DidCommRoutingService.js');
const require_DidCommMessagePickupApi = require('../message-pickup/DidCommMessagePickupApi.js');
const require_DidCommBatchPickupMessage = require('../message-pickup/protocol/v1/messages/DidCommBatchPickupMessage.js');
require('../message-pickup/protocol/v1/index.js');
const require_DidCommStatusV2Message = require('../message-pickup/protocol/v2/messages/DidCommStatusV2Message.js');
require('../message-pickup/protocol/v2/index.js');
require('./repository/index.js');
const require_DidCommDiscoverFeaturesApi = require('../discover-features/DidCommDiscoverFeaturesApi.js');
require('../discover-features/index.js');
const require_DidCommMediationRecipientModuleConfig = require('./DidCommMediationRecipientModuleConfig.js');
let __credo_ts_core = require("@credo-ts/core");
__credo_ts_core = require_rolldown_runtime.__toESM(__credo_ts_core);

//#region ../didcomm/src/modules/routing/DidCommMediationRecipientApi.ts
var import_cjs = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$1.require_cjs());
var import_operators = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$3.require_operators());
var _ref, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10, _ref11, _ref12;
let DidCommMediationRecipientApi = class DidCommMediationRecipientApi$1 {
	constructor(mediationRecipientService, connectionService, dids, messageSender, eventEmitter, discoverFeaturesApi, messagePickupApi, mediationRepository, routingService, logger, agentContext, stop$, mediationRecipientModuleConfig) {
		this.stopMessagePickup$ = new import_cjs.Subject();
		this.connectionService = connectionService;
		this.dids = dids;
		this.mediationRecipientService = mediationRecipientService;
		this.messageSender = messageSender;
		this.eventEmitter = eventEmitter;
		this.logger = logger;
		this.discoverFeaturesApi = discoverFeaturesApi;
		this.messagePickupApi = messagePickupApi;
		this.mediationRepository = mediationRepository;
		this.routingService = routingService;
		this.agentContext = agentContext;
		this.stop$ = stop$;
		this.config = mediationRecipientModuleConfig;
	}
	async sendMessage(outboundMessageContext, pickupStrategy) {
		const transportPriority = (pickupStrategy ?? this.config.mediatorPickupStrategy) === require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.Implicit ? {
			schemes: ["wss", "ws"],
			restrictive: true
		} : void 0;
		await this.messageSender.sendMessage(outboundMessageContext, { transportPriority });
	}
	/**
	* Implicit mode consists simply on initiating a long-lived session to a mediator and wait for the
	* messages to arrive automatically.
	*
	* In order to do initiate this session, we open a suitable connection (using WebSocket transport) and
	* send a Trust Ping message.
	*
	* @param mediator
	*/
	async initiateImplicitMode(mediator) {
		const connection = await this.connectionService.getById(this.agentContext, mediator.connectionId);
		const { message, connectionRecord } = await this.connectionService.createTrustPing(this.agentContext, connection, { responseRequested: false });
		const websocketSchemes = ["ws", "wss"];
		if (!((connectionRecord.theirDid && await this.dids.resolveDidDocument(connectionRecord.theirDid))?.didCommServices || [])?.some((s) => websocketSchemes.includes(s.protocolScheme))) throw new __credo_ts_core.CredoError("Cannot open websocket to connection without websocket service endpoint");
		await this.messageSender.sendMessage(new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(message, {
			agentContext: this.agentContext,
			connection: connectionRecord
		}), { transportPriority: {
			schemes: websocketSchemes,
			restrictive: true
		} });
	}
	/**
	* Keep track of a persistent transport session with a mediator, trying to reconnect to it as
	* soon as it is disconnected, using a recursive back-off strategy
	*
	* @param mediator mediation record
	* @param pickupStrategy chosen pick up strategy (should be Implicit or PickUp in Live Mode)
	*/
	async monitorMediatorWebSocketEvents(mediator, pickupStrategy) {
		const { baseMediatorReconnectionIntervalMs, maximumMediatorReconnectionIntervalMs } = this.config;
		let interval$1 = baseMediatorReconnectionIntervalMs;
		const stopConditions$ = (0, import_cjs.merge)(this.stop$, this.stopMessagePickup$).pipe();
		this.eventEmitter.observable(require_DidCommTransportEventTypes.DidCommTransportEventTypes.DidCommOutboundWebSocketOpenedEvent).pipe((0, import_operators.takeUntil)(stopConditions$), (0, import_operators.filter)((e) => e.payload.connectionId === mediator.connectionId)).subscribe(() => {
			interval$1 = baseMediatorReconnectionIntervalMs;
		});
		this.eventEmitter.observable(require_DidCommTransportEventTypes.DidCommTransportEventTypes.DidCommOutboundWebSocketClosedEvent).pipe((0, import_operators.takeUntil)(stopConditions$), (0, import_operators.filter)((e) => e.payload.connectionId === mediator.connectionId), (0, import_operators.throttleTime)(interval$1), (0, import_operators.delayWhen)(() => (0, import_cjs.timer)(interval$1)), (0, import_operators.tap)(() => {
			interval$1 = Math.min(interval$1 * 2, maximumMediatorReconnectionIntervalMs);
		})).subscribe({
			next: async () => {
				this.logger.debug(`Websocket connection to mediator with connectionId '${mediator.connectionId}' is closed, attempting to reconnect...`);
				try {
					if (pickupStrategy === require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV2LiveMode) {
						await this.messagePickupApi.pickupMessages({
							connectionId: mediator.connectionId,
							protocolVersion: "v2",
							awaitCompletion: true
						});
						await this.messagePickupApi.setLiveDeliveryMode({
							connectionId: mediator.connectionId,
							liveDelivery: true,
							protocolVersion: "v2"
						});
					} else await this.initiateImplicitMode(mediator);
				} catch (error) {
					this.logger.warn("Unable to re-open websocket connection to mediator", { error });
				}
			},
			complete: () => this.logger.info(`Stopping pickup of messages from mediator '${mediator.id}'`)
		});
	}
	/**
	* Start a Message Pickup flow with a registered Mediator.
	*
	* @param mediator optional {MediationRecord} corresponding to the mediator to pick messages from. It will use
	* default mediator otherwise
	* @param pickupStrategy optional {DidCommMediatorPickupStrategy} to use in the loop. It will use Agent's default
	* strategy or attempt to find it by Discover Features otherwise
	* @returns
	*/
	async initiateMessagePickup(mediator, pickupStrategy) {
		const { mediatorPollingInterval } = this.config;
		const mediatorRecord = mediator ?? await this.findDefaultMediator();
		if (!mediatorRecord) throw new __credo_ts_core.CredoError("There is no mediator to pickup messages from");
		const mediatorPickupStrategy = pickupStrategy ?? await this.getPickupStrategyForMediator(mediatorRecord);
		const mediatorConnection = await this.connectionService.getById(this.agentContext, mediatorRecord.connectionId);
		switch (mediatorPickupStrategy) {
			case require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV1:
			case require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV2: {
				const stopConditions$ = (0, import_cjs.merge)(this.stop$, this.stopMessagePickup$).pipe();
				const protocolVersion = mediatorPickupStrategy === require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV2 ? "v2" : "v1";
				this.logger.info(`Starting explicit pickup of messages from mediator '${mediatorRecord.id}' using ${protocolVersion}`);
				return (0, import_cjs.interval)(mediatorPollingInterval).pipe((0, import_operators.takeUntil)(stopConditions$)).subscribe({
					next: async () => {
						await this.messagePickupApi.pickupMessages({
							connectionId: mediatorConnection.id,
							batchSize: this.config.maximumMessagePickup,
							protocolVersion
						});
					},
					complete: () => this.logger.info(`Stopping pickup of messages from mediator '${mediatorRecord.id}'`)
				});
			}
			case require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV2LiveMode:
				this.logger.info(`Starting Live Mode pickup of messages from mediator '${mediatorRecord.id}'`);
				await this.monitorMediatorWebSocketEvents(mediatorRecord, mediatorPickupStrategy);
				await this.messagePickupApi.pickupMessages({
					connectionId: mediatorConnection.id,
					protocolVersion: "v2",
					awaitCompletion: true
				});
				await this.messagePickupApi.setLiveDeliveryMode({
					connectionId: mediatorConnection.id,
					liveDelivery: true,
					protocolVersion: "v2"
				});
				break;
			case require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.Implicit:
				this.logger.info(`Starting implicit pickup of messages from mediator '${mediatorRecord.id}'`);
				await this.monitorMediatorWebSocketEvents(mediatorRecord, mediatorPickupStrategy);
				await this.initiateImplicitMode(mediatorRecord);
				break;
			default: this.logger.info(`Skipping pickup of messages from mediator '${mediatorRecord.id}' due to pickup strategy none`);
		}
	}
	/**
	* Terminate all ongoing Message Pickup loops
	*/
	async stopMessagePickup() {
		this.stopMessagePickup$.next(true);
	}
	async getPickupStrategyForMediator(mediator) {
		let mediatorPickupStrategy = mediator.pickupStrategy ?? this.config.mediatorPickupStrategy;
		if (!mediatorPickupStrategy) {
			if ((await this.discoverFeaturesApi.queryFeatures({
				connectionId: mediator.connectionId,
				protocolVersion: "v1",
				queries: [{
					featureType: "protocol",
					match: require_DidCommStatusV2Message.DidCommStatusV2Message.type.protocolUri
				}],
				awaitDisclosures: true
			})).features?.find((item) => item.id === require_DidCommStatusV2Message.DidCommStatusV2Message.type.protocolUri)) mediatorPickupStrategy = require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV2;
			else mediatorPickupStrategy = (await this.discoverFeaturesApi.queryFeatures({
				connectionId: mediator.connectionId,
				protocolVersion: "v1",
				queries: [{
					featureType: "protocol",
					match: require_DidCommBatchPickupMessage.DidCommBatchPickupMessage.type.protocolUri
				}],
				awaitDisclosures: true
			})).features?.find((item) => item.id === require_DidCommBatchPickupMessage.DidCommBatchPickupMessage.type.protocolUri) ? require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.PickUpV1 : require_DidCommMediatorPickupStrategy.DidCommMediatorPickupStrategy.Implicit;
			mediator.pickupStrategy = mediatorPickupStrategy;
			await this.mediationRepository.update(this.agentContext, mediator);
		}
		return mediatorPickupStrategy;
	}
	async discoverMediation() {
		return this.mediationRecipientService.discoverMediation(this.agentContext);
	}
	async setDefaultMediator(mediatorRecord) {
		return this.mediationRecipientService.setDefaultMediator(this.agentContext, mediatorRecord);
	}
	async requestMediation(connection) {
		const { mediationRecord, message } = await this.mediationRecipientService.createRequest(this.agentContext, connection);
		const outboundMessage = new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(message, {
			agentContext: this.agentContext,
			connection
		});
		await this.sendMessage(outboundMessage);
		return mediationRecord;
	}
	async notifyKeylistUpdate(connection, verkey, action) {
		let useDidKey = this.agentContext.dependencyManager.resolve(require_DidCommModuleConfig.DidCommModuleConfig).useDidKeyInProtocols;
		const useDidKeysConnectionMetadata = connection.metadata.get(require_DidCommConnectionMetadataTypes.DidCommConnectionMetadataKeys.UseDidKeysForProtocol);
		if (useDidKeysConnectionMetadata) useDidKey = useDidKeysConnectionMetadata[require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateMessage.type.protocolUri] ?? useDidKey;
		const outboundMessageContext = new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(this.mediationRecipientService.createKeylistUpdateMessage([new require_DidCommKeylistUpdateMessage.DidCommKeylistUpdate({
			action: action ?? require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateAction.add,
			recipientKey: useDidKey ? (0, __credo_ts_core.verkeyToDidKey)(verkey) : verkey
		})]), {
			agentContext: this.agentContext,
			connection
		});
		await this.sendMessage(outboundMessageContext);
	}
	async findByConnectionId(connectionId) {
		return await this.mediationRecipientService.findByConnectionId(this.agentContext, connectionId);
	}
	async getMediators() {
		return await this.mediationRecipientService.getMediators(this.agentContext);
	}
	async findDefaultMediator() {
		return this.mediationRecipientService.findDefaultMediator(this.agentContext);
	}
	async findDefaultMediatorConnection() {
		const mediatorRecord = await this.findDefaultMediator();
		if (mediatorRecord) return this.connectionService.getById(this.agentContext, mediatorRecord.connectionId);
		return null;
	}
	async requestAndAwaitGrant(connection, timeoutMs = 1e4) {
		const { mediationRecord, message } = await this.mediationRecipientService.createRequest(this.agentContext, connection);
		const observable = this.eventEmitter.observable(require_DidCommRoutingEvents.DidCommRoutingEventTypes.MediationStateChanged);
		const subject = new import_cjs.ReplaySubject(1);
		observable.pipe((0, __credo_ts_core.filterContextCorrelationId)(this.agentContext.contextCorrelationId), (0, import_operators.filter)((event) => event.payload.mediationRecord.id === mediationRecord.id), (0, import_operators.filter)((event) => event.payload.previousState === require_DidCommMediationState.DidCommMediationState.Requested), (0, import_operators.filter)((event) => event.payload.mediationRecord.state === require_DidCommMediationState.DidCommMediationState.Granted), (0, import_operators.first)(), (0, import_operators.timeout)({
			first: timeoutMs,
			meta: "MediationRecipientApi.requestAndAwaitGrant"
		})).subscribe(subject);
		const outboundMessageContext = new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(message, {
			agentContext: this.agentContext,
			connection,
			associatedRecord: mediationRecord
		});
		await this.sendMessage(outboundMessageContext);
		return (await (0, import_cjs.firstValueFrom)(subject)).payload.mediationRecord;
	}
	/**
	* Requests mediation for a given connection and sets that as default mediator.
	*
	* @param connection connection record which will be used for mediation
	* @returns mediation record
	*/
	async provision(connection) {
		this.logger.debug("Connection completed, requesting mediation");
		let mediation = await this.findByConnectionId(connection.id);
		if (!mediation) {
			this.logger.info(`Requesting mediation for connection ${connection.id}`);
			mediation = await this.requestAndAwaitGrant(connection, 6e4);
			this.logger.debug("Mediation granted, setting as default mediator");
			await this.setDefaultMediator(mediation);
			this.logger.debug("Default mediator set");
		} else this.logger.debug(`Mediator invitation has already been ${mediation.isReady ? "granted" : "requested"}`);
		return mediation;
	}
	async getRouting(options) {
		return this.routingService.getRouting(this.agentContext, options);
	}
};
DidCommMediationRecipientApi = require_decorate.__decorate([
	(0, __credo_ts_core.injectable)(),
	require_decorateParam.__decorateParam(9, (0, __credo_ts_core.inject)(__credo_ts_core.InjectionSymbols.Logger)),
	require_decorateParam.__decorateParam(11, (0, __credo_ts_core.inject)(__credo_ts_core.InjectionSymbols.Stop$)),
	require_decorateMetadata.__decorateMetadata("design:paramtypes", [
		typeof (_ref = typeof require_DidCommMediationRecipientService.DidCommMediationRecipientService !== "undefined" && require_DidCommMediationRecipientService.DidCommMediationRecipientService) === "function" ? _ref : Object,
		typeof (_ref2 = typeof require_DidCommConnectionService.DidCommConnectionService !== "undefined" && require_DidCommConnectionService.DidCommConnectionService) === "function" ? _ref2 : Object,
		typeof (_ref3 = typeof __credo_ts_core.DidsApi !== "undefined" && __credo_ts_core.DidsApi) === "function" ? _ref3 : Object,
		typeof (_ref4 = typeof require_DidCommMessageSender.DidCommMessageSender !== "undefined" && require_DidCommMessageSender.DidCommMessageSender) === "function" ? _ref4 : Object,
		typeof (_ref5 = typeof __credo_ts_core.EventEmitter !== "undefined" && __credo_ts_core.EventEmitter) === "function" ? _ref5 : Object,
		typeof (_ref6 = typeof require_DidCommDiscoverFeaturesApi.DidCommDiscoverFeaturesApi !== "undefined" && require_DidCommDiscoverFeaturesApi.DidCommDiscoverFeaturesApi) === "function" ? _ref6 : Object,
		typeof (_ref7 = typeof require_DidCommMessagePickupApi.DidCommMessagePickupApi !== "undefined" && require_DidCommMessagePickupApi.DidCommMessagePickupApi) === "function" ? _ref7 : Object,
		typeof (_ref8 = typeof require_DidCommMediationRepository.DidCommMediationRepository !== "undefined" && require_DidCommMediationRepository.DidCommMediationRepository) === "function" ? _ref8 : Object,
		typeof (_ref9 = typeof require_DidCommRoutingService.DidCommRoutingService !== "undefined" && require_DidCommRoutingService.DidCommRoutingService) === "function" ? _ref9 : Object,
		Object,
		typeof (_ref10 = typeof __credo_ts_core.AgentContext !== "undefined" && __credo_ts_core.AgentContext) === "function" ? _ref10 : Object,
		typeof (_ref11 = typeof import_cjs.Subject !== "undefined" && import_cjs.Subject) === "function" ? _ref11 : Object,
		typeof (_ref12 = typeof require_DidCommMediationRecipientModuleConfig.DidCommMediationRecipientModuleConfig !== "undefined" && require_DidCommMediationRecipientModuleConfig.DidCommMediationRecipientModuleConfig) === "function" ? _ref12 : Object
	])
], DidCommMediationRecipientApi);

//#endregion
Object.defineProperty(exports, 'DidCommMediationRecipientApi', {
  enumerable: true,
  get: function () {
    return DidCommMediationRecipientApi;
  }
});