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_DidCommConnectionType = require('../../connections/models/DidCommConnectionType.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_index$2 = 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');
const require_DidCommKeylistUpdateResponseMessage = require('../messages/DidCommKeylistUpdateResponseMessage.js');
const require_DidCommMediationGrantMessage = require('../messages/DidCommMediationGrantMessage.js');
const require_DidCommMediationRequestMessage = require('../messages/DidCommMediationRequestMessage.js');
require('../messages/index.js');
const require_DidCommMediationRole = require('../models/DidCommMediationRole.js');
const require_DidCommMediationState = require('../models/DidCommMediationState.js');
const require_DidCommMediationRecord = require('../repository/DidCommMediationRecord.js');
const require_DidCommMediationRepository = require('../repository/DidCommMediationRepository.js');
let __credo_ts_core = require("@credo-ts/core");
__credo_ts_core = require_rolldown_runtime.__toESM(__credo_ts_core);

//#region ../didcomm/src/modules/routing/services/DidCommMediationRecipientService.ts
var import_cjs = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$1.require_cjs());
var import_operators = /* @__PURE__ */ require_rolldown_runtime.__toESM(require_index$2.require_operators());
var _ref, _ref2, _ref3, _ref4;
let DidCommMediationRecipientService = class DidCommMediationRecipientService$1 {
	constructor(connectionService, messageSender, mediatorRepository, eventEmitter) {
		this.mediationRepository = mediatorRepository;
		this.eventEmitter = eventEmitter;
		this.connectionService = connectionService;
		this.messageSender = messageSender;
	}
	async createRequest(agentContext, connection) {
		const message = new require_DidCommMediationRequestMessage.DidCommMediationRequestMessage({});
		const mediationRecord = new require_DidCommMediationRecord.DidCommMediationRecord({
			threadId: message.threadId,
			state: require_DidCommMediationState.DidCommMediationState.Requested,
			role: require_DidCommMediationRole.DidCommMediationRole.Recipient,
			connectionId: connection.id
		});
		await this.connectionService.addConnectionType(agentContext, connection, require_DidCommConnectionType.DidCommConnectionType.Mediator);
		await this.mediationRepository.save(agentContext, mediationRecord);
		this.emitStateChangedEvent(agentContext, mediationRecord, null);
		return {
			mediationRecord,
			message
		};
	}
	async processMediationGrant(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const mediationRecord = await this.mediationRepository.getByConnectionId(messageContext.agentContext, connection.id);
		mediationRecord.assertState(require_DidCommMediationState.DidCommMediationState.Requested);
		mediationRecord.assertRole(require_DidCommMediationRole.DidCommMediationRole.Recipient);
		mediationRecord.endpoint = messageContext.message.endpoint;
		const connectionUsesDidKey = messageContext.message.routingKeys.some(__credo_ts_core.isDidKey);
		await this.updateUseDidKeysFlag(messageContext.agentContext, connection, require_DidCommMediationGrantMessage.DidCommMediationGrantMessage.type.protocolUri, connectionUsesDidKey);
		mediationRecord.routingKeys = messageContext.message.routingKeys.map(__credo_ts_core.didKeyToVerkey);
		return await this.updateState(messageContext.agentContext, mediationRecord, require_DidCommMediationState.DidCommMediationState.Granted);
	}
	async processKeylistUpdateResults(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const mediationRecord = await this.mediationRepository.getByConnectionId(messageContext.agentContext, connection.id);
		mediationRecord.assertReady();
		mediationRecord.assertRole(require_DidCommMediationRole.DidCommMediationRole.Recipient);
		const keylist = messageContext.message.updated;
		const connectionUsesDidKey = keylist.some((key) => (0, __credo_ts_core.isDidKey)(key.recipientKey));
		await this.updateUseDidKeysFlag(messageContext.agentContext, connection, require_DidCommKeylistUpdateResponseMessage.DidCommKeylistUpdateResponseMessage.type.protocolUri, connectionUsesDidKey);
		for (const update of keylist) if (update.action === require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateAction.add) mediationRecord.addRecipientKey((0, __credo_ts_core.didKeyToVerkey)(update.recipientKey));
		else if (update.action === require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateAction.remove) mediationRecord.removeRecipientKey((0, __credo_ts_core.didKeyToVerkey)(update.recipientKey));
		await this.mediationRepository.update(messageContext.agentContext, mediationRecord);
		this.eventEmitter.emit(messageContext.agentContext, {
			type: require_DidCommRoutingEvents.DidCommRoutingEventTypes.RecipientKeylistUpdated,
			payload: {
				mediationRecord,
				keylist
			}
		});
	}
	async keylistUpdateAndAwait(agentContext, mediationRecord, updates, timeoutMs = 15e3) {
		const connection = await this.connectionService.getById(agentContext, mediationRecord.connectionId);
		let useDidKey = 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 message = this.createKeylistUpdateMessage(updates.map((item) => new require_DidCommKeylistUpdateMessage.DidCommKeylistUpdate({
			action: item.action,
			recipientKey: useDidKey ? new __credo_ts_core.DidKey(item.recipientKey).did : __credo_ts_core.TypedArrayEncoder.toBase58(item.recipientKey.publicKey.publicKey)
		})));
		mediationRecord.assertReady();
		mediationRecord.assertRole(require_DidCommMediationRole.DidCommMediationRole.Recipient);
		const observable = this.eventEmitter.observable(require_DidCommRoutingEvents.DidCommRoutingEventTypes.RecipientKeylistUpdated);
		const subject = new import_cjs.ReplaySubject(1);
		observable.pipe((0, __credo_ts_core.filterContextCorrelationId)(agentContext.contextCorrelationId), (0, import_operators.filter)((event) => mediationRecord.id === event.payload.mediationRecord.id), (0, import_operators.first)(), (0, import_operators.timeout)({
			first: timeoutMs,
			meta: "DidCommMediationRecipientService.keylistUpdateAndAwait"
		})).subscribe(subject);
		const outboundMessageContext = new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(message, {
			agentContext,
			connection
		});
		await this.messageSender.sendMessage(outboundMessageContext);
		return (await (0, import_cjs.firstValueFrom)(subject)).payload.mediationRecord;
	}
	createKeylistUpdateMessage(updates) {
		return new require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateMessage({ updates });
	}
	async addMediationRouting(agentContext, routing, { mediatorId, useDefaultMediator = true } = {}) {
		let mediationRecord = null;
		if (mediatorId) mediationRecord = await this.getById(agentContext, mediatorId);
		else if (useDefaultMediator) mediationRecord = await this.findDefaultMediator(agentContext);
		if (!mediationRecord) return routing;
		mediationRecord = await this.keylistUpdateAndAwait(agentContext, mediationRecord, [{
			recipientKey: routing.recipientKey,
			action: require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateAction.add
		}]);
		return {
			...routing,
			mediatorId: mediationRecord.id,
			endpoints: mediationRecord.endpoint ? [mediationRecord.endpoint] : routing.endpoints,
			routingKeys: mediationRecord.routingKeys.map((key) => __credo_ts_core.Kms.PublicJwk.fromPublicKey({
				kty: "OKP",
				crv: "Ed25519",
				publicKey: __credo_ts_core.TypedArrayEncoder.fromBase58(key)
			}))
		};
	}
	async removeMediationRouting(agentContext, { recipientKeys, mediatorId }) {
		const mediationRecord = await this.getById(agentContext, mediatorId);
		if (!mediationRecord) throw new __credo_ts_core.CredoError("No mediation record to remove routing from has been found");
		await this.keylistUpdateAndAwait(agentContext, mediationRecord, recipientKeys.map((item) => {
			return {
				recipientKey: item,
				action: require_DidCommKeylistUpdateMessage.DidCommKeylistUpdateAction.remove
			};
		}));
	}
	async processMediationDeny(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const mediationRecord = await this.findByConnectionId(messageContext.agentContext, connection.id);
		if (!mediationRecord) throw new Error(`No mediation has been requested for this connection id: ${connection.id}`);
		mediationRecord.assertRole(require_DidCommMediationRole.DidCommMediationRole.Recipient);
		mediationRecord.assertState(require_DidCommMediationState.DidCommMediationState.Requested);
		await this.updateState(messageContext.agentContext, mediationRecord, require_DidCommMediationState.DidCommMediationState.Denied);
		return mediationRecord;
	}
	/**
	* Update the record to a new state and emit an state changed event. Also updates the record
	* in storage.
	*
	* @param MediationRecord The proof record to update the state for
	* @param newState The state to update to
	*
	*/
	async updateState(agentContext, mediationRecord, newState) {
		const previousState = mediationRecord.state;
		mediationRecord.state = newState;
		await this.mediationRepository.update(agentContext, mediationRecord);
		this.emitStateChangedEvent(agentContext, mediationRecord, previousState);
		return mediationRecord;
	}
	emitStateChangedEvent(agentContext, mediationRecord, previousState) {
		this.eventEmitter.emit(agentContext, {
			type: require_DidCommRoutingEvents.DidCommRoutingEventTypes.MediationStateChanged,
			payload: {
				mediationRecord: mediationRecord.clone(),
				previousState
			}
		});
	}
	async getById(agentContext, id) {
		return this.mediationRepository.getById(agentContext, id);
	}
	async findByConnectionId(agentContext, connectionId) {
		return this.mediationRepository.findSingleByQuery(agentContext, { connectionId });
	}
	async getMediators(agentContext) {
		return this.mediationRepository.getAll(agentContext);
	}
	async findAllMediatorsByQuery(agentContext, query, queryOptions) {
		return await this.mediationRepository.findByQuery(agentContext, query, queryOptions);
	}
	async findDefaultMediator(agentContext) {
		return this.mediationRepository.findSingleByQuery(agentContext, { default: true });
	}
	async discoverMediation(agentContext, mediatorId) {
		if (mediatorId) return this.mediationRepository.getById(agentContext, mediatorId);
		const defaultMediator = await this.findDefaultMediator(agentContext);
		if (defaultMediator) {
			if (defaultMediator.state !== require_DidCommMediationState.DidCommMediationState.Granted) throw new __credo_ts_core.CredoError(`Mediation State for ${defaultMediator.id} is not granted, but is set as default mediator!`);
			return defaultMediator;
		}
	}
	async setDefaultMediator(agentContext, mediator) {
		const mediationRecords = await this.mediationRepository.findByQuery(agentContext, { default: true });
		for (const record of mediationRecords) {
			record.setTag("default", false);
			await this.mediationRepository.update(agentContext, record);
		}
		mediator.setTag("default", true);
		await this.mediationRepository.update(agentContext, mediator);
	}
	async clearDefaultMediator(agentContext) {
		const mediationRecord = await this.findDefaultMediator(agentContext);
		if (mediationRecord) {
			mediationRecord.setTag("default", false);
			await this.mediationRepository.update(agentContext, mediationRecord);
		}
	}
	async updateUseDidKeysFlag(agentContext, connection, protocolUri, connectionUsesDidKey) {
		const useDidKeysForProtocol = connection.metadata.get(require_DidCommConnectionMetadataTypes.DidCommConnectionMetadataKeys.UseDidKeysForProtocol) ?? {};
		useDidKeysForProtocol[protocolUri] = connectionUsesDidKey;
		connection.metadata.set(require_DidCommConnectionMetadataTypes.DidCommConnectionMetadataKeys.UseDidKeysForProtocol, useDidKeysForProtocol);
		await this.connectionService.update(agentContext, connection);
	}
};
DidCommMediationRecipientService = require_decorate.__decorate([(0, __credo_ts_core.injectable)(), require_decorateMetadata.__decorateMetadata("design:paramtypes", [
	typeof (_ref = typeof require_DidCommConnectionService.DidCommConnectionService !== "undefined" && require_DidCommConnectionService.DidCommConnectionService) === "function" ? _ref : Object,
	typeof (_ref2 = typeof require_DidCommMessageSender.DidCommMessageSender !== "undefined" && require_DidCommMessageSender.DidCommMessageSender) === "function" ? _ref2 : Object,
	typeof (_ref3 = typeof require_DidCommMediationRepository.DidCommMediationRepository !== "undefined" && require_DidCommMediationRepository.DidCommMediationRepository) === "function" ? _ref3 : Object,
	typeof (_ref4 = typeof __credo_ts_core.EventEmitter !== "undefined" && __credo_ts_core.EventEmitter) === "function" ? _ref4 : Object
])], DidCommMediationRecipientService);

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