import { __decorateMetadata } from "../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateMetadata.mjs";
import { __decorate } from "../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.mjs";
import { DidCommOutboundMessageContext } from "../../../models/DidCommOutboundMessageContext.mjs";
import "../../../models/index.mjs";
import { DidCommConnectionType } from "../../connections/models/DidCommConnectionType.mjs";
import { ReplaySubject } from "../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/ReplaySubject.mjs";
import { firstValueFrom } from "../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/firstValueFrom.mjs";
import { timeout } from "../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/operators/timeout.mjs";
import { filter } from "../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/operators/filter.mjs";
import { first } from "../../../../../../node_modules/.pnpm/rxjs@7.8.2/node_modules/rxjs/dist/esm5/internal/operators/first.mjs";
import { DidCommModuleConfig } from "../../../DidCommModuleConfig.mjs";
import { DidCommConnectionService } from "../../connections/services/DidCommConnectionService.mjs";
import { DidCommMessageSender } from "../../../DidCommMessageSender.mjs";
import { DidCommConnectionMetadataKeys } from "../../connections/repository/DidCommConnectionMetadataTypes.mjs";
import { DidCommRoutingEventTypes } from "../DidCommRoutingEvents.mjs";
import { DidCommKeylistUpdate, DidCommKeylistUpdateAction, DidCommKeylistUpdateMessage } from "../messages/DidCommKeylistUpdateMessage.mjs";
import { DidCommKeylistUpdateResponseMessage } from "../messages/DidCommKeylistUpdateResponseMessage.mjs";
import { DidCommMediationGrantMessage } from "../messages/DidCommMediationGrantMessage.mjs";
import { DidCommMediationRequestMessage } from "../messages/DidCommMediationRequestMessage.mjs";
import "../messages/index.mjs";
import { DidCommMediationRole } from "../models/DidCommMediationRole.mjs";
import { DidCommMediationState } from "../models/DidCommMediationState.mjs";
import { DidCommMediationRecord } from "../repository/DidCommMediationRecord.mjs";
import { DidCommMediationRepository } from "../repository/DidCommMediationRepository.mjs";
import { AgentContext, CredoError, DidKey, EventEmitter, Kms, TypedArrayEncoder, didKeyToVerkey, filterContextCorrelationId, injectable, isDidKey } from "@credo-ts/core";

//#region ../didcomm/src/modules/routing/services/DidCommMediationRecipientService.ts
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 DidCommMediationRequestMessage({});
		const mediationRecord = new DidCommMediationRecord({
			threadId: message.threadId,
			state: DidCommMediationState.Requested,
			role: DidCommMediationRole.Recipient,
			connectionId: connection.id
		});
		await this.connectionService.addConnectionType(agentContext, connection, 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(DidCommMediationState.Requested);
		mediationRecord.assertRole(DidCommMediationRole.Recipient);
		mediationRecord.endpoint = messageContext.message.endpoint;
		const connectionUsesDidKey = messageContext.message.routingKeys.some(isDidKey);
		await this.updateUseDidKeysFlag(messageContext.agentContext, connection, DidCommMediationGrantMessage.type.protocolUri, connectionUsesDidKey);
		mediationRecord.routingKeys = messageContext.message.routingKeys.map(didKeyToVerkey);
		return await this.updateState(messageContext.agentContext, mediationRecord, DidCommMediationState.Granted);
	}
	async processKeylistUpdateResults(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const mediationRecord = await this.mediationRepository.getByConnectionId(messageContext.agentContext, connection.id);
		mediationRecord.assertReady();
		mediationRecord.assertRole(DidCommMediationRole.Recipient);
		const keylist = messageContext.message.updated;
		const connectionUsesDidKey = keylist.some((key) => isDidKey(key.recipientKey));
		await this.updateUseDidKeysFlag(messageContext.agentContext, connection, DidCommKeylistUpdateResponseMessage.type.protocolUri, connectionUsesDidKey);
		for (const update of keylist) if (update.action === DidCommKeylistUpdateAction.add) mediationRecord.addRecipientKey(didKeyToVerkey(update.recipientKey));
		else if (update.action === DidCommKeylistUpdateAction.remove) mediationRecord.removeRecipientKey(didKeyToVerkey(update.recipientKey));
		await this.mediationRepository.update(messageContext.agentContext, mediationRecord);
		this.eventEmitter.emit(messageContext.agentContext, {
			type: 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(DidCommModuleConfig).useDidKeyInProtocols;
		const useDidKeysConnectionMetadata = connection.metadata.get(DidCommConnectionMetadataKeys.UseDidKeysForProtocol);
		if (useDidKeysConnectionMetadata) useDidKey = useDidKeysConnectionMetadata[DidCommKeylistUpdateMessage.type.protocolUri] ?? useDidKey;
		const message = this.createKeylistUpdateMessage(updates.map((item) => new DidCommKeylistUpdate({
			action: item.action,
			recipientKey: useDidKey ? new DidKey(item.recipientKey).did : TypedArrayEncoder.toBase58(item.recipientKey.publicKey.publicKey)
		})));
		mediationRecord.assertReady();
		mediationRecord.assertRole(DidCommMediationRole.Recipient);
		const observable = this.eventEmitter.observable(DidCommRoutingEventTypes.RecipientKeylistUpdated);
		const subject = new ReplaySubject(1);
		observable.pipe(filterContextCorrelationId(agentContext.contextCorrelationId), filter((event) => mediationRecord.id === event.payload.mediationRecord.id), first(), timeout({
			first: timeoutMs,
			meta: "DidCommMediationRecipientService.keylistUpdateAndAwait"
		})).subscribe(subject);
		const outboundMessageContext = new DidCommOutboundMessageContext(message, {
			agentContext,
			connection
		});
		await this.messageSender.sendMessage(outboundMessageContext);
		return (await firstValueFrom(subject)).payload.mediationRecord;
	}
	createKeylistUpdateMessage(updates) {
		return new 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: DidCommKeylistUpdateAction.add
		}]);
		return {
			...routing,
			mediatorId: mediationRecord.id,
			endpoints: mediationRecord.endpoint ? [mediationRecord.endpoint] : routing.endpoints,
			routingKeys: mediationRecord.routingKeys.map((key) => Kms.PublicJwk.fromPublicKey({
				kty: "OKP",
				crv: "Ed25519",
				publicKey: TypedArrayEncoder.fromBase58(key)
			}))
		};
	}
	async removeMediationRouting(agentContext, { recipientKeys, mediatorId }) {
		const mediationRecord = await this.getById(agentContext, mediatorId);
		if (!mediationRecord) throw new CredoError("No mediation record to remove routing from has been found");
		await this.keylistUpdateAndAwait(agentContext, mediationRecord, recipientKeys.map((item) => {
			return {
				recipientKey: item,
				action: 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(DidCommMediationRole.Recipient);
		mediationRecord.assertState(DidCommMediationState.Requested);
		await this.updateState(messageContext.agentContext, mediationRecord, 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: 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 !== DidCommMediationState.Granted) throw new 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(DidCommConnectionMetadataKeys.UseDidKeysForProtocol) ?? {};
		useDidKeysForProtocol[protocolUri] = connectionUsesDidKey;
		connection.metadata.set(DidCommConnectionMetadataKeys.UseDidKeysForProtocol, useDidKeysForProtocol);
		await this.connectionService.update(agentContext, connection);
	}
};
DidCommMediationRecipientService = __decorate([injectable(), __decorateMetadata("design:paramtypes", [
	typeof (_ref = typeof DidCommConnectionService !== "undefined" && DidCommConnectionService) === "function" ? _ref : Object,
	typeof (_ref2 = typeof DidCommMessageSender !== "undefined" && DidCommMessageSender) === "function" ? _ref2 : Object,
	typeof (_ref3 = typeof DidCommMediationRepository !== "undefined" && DidCommMediationRepository) === "function" ? _ref3 : Object,
	typeof (_ref4 = typeof EventEmitter !== "undefined" && EventEmitter) === "function" ? _ref4 : Object
])], DidCommMediationRecipientService);

//#endregion
export { DidCommMediationRecipientService };
//# sourceMappingURL=DidCommMediationRecipientService.mjs.map