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_messageType = require('./util/messageType.js');
const require_DidCommMessage = require('./DidCommMessage.js');
const require_DidCommProblemReportMessage = require('./messages/problem-reports/DidCommProblemReportMessage.js');
const require_DidCommProblemReportError = require('./errors/problem-reports/DidCommProblemReportError.js');
require('./errors/index.js');
require('./messages/index.js');
const require_DidCommProblemReportReason = require('./models/problem-reports/DidCommProblemReportReason.js');
const require_DidCommInboundMessageContext = require('./models/DidCommInboundMessageContext.js');
const require_DidCommOutboundMessageContext = require('./models/DidCommOutboundMessageContext.js');
require('./models/index.js');
const require_JWE = require('./util/JWE.js');
const require_DidCommTransportService = require('./DidCommTransportService.js');
const require_decorateParam = require('../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.js');
const require_DidCommConnectionService = require('./modules/connections/services/DidCommConnectionService.js');
const require_DidCommEnvelopeService = require('./DidCommEnvelopeService.js');
const require_DidCommMessageSender = require('./DidCommMessageSender.js');
require('./modules/connections/services/index.js');
const require_DidCommMessageHandlerRegistry = require('./DidCommMessageHandlerRegistry.js');
const require_DidCommDispatcher = require('./DidCommDispatcher.js');
let __credo_ts_core = require("@credo-ts/core");
__credo_ts_core = require_rolldown_runtime.__toESM(__credo_ts_core);

//#region ../didcomm/src/DidCommMessageReceiver.ts
var _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
let DidCommMessageReceiver = class DidCommMessageReceiver$1 {
	constructor(envelopeService, transportService, messageSender, connectionService, dispatcher, messageHandlerRegistry, agentContextProvider, logger) {
		this._inboundTransports = [];
		this.envelopeService = envelopeService;
		this.transportService = transportService;
		this.messageSender = messageSender;
		this.connectionService = connectionService;
		this.dispatcher = dispatcher;
		this.messageHandlerRegistry = messageHandlerRegistry;
		this.agentContextProvider = agentContextProvider;
		this.logger = logger;
		this._inboundTransports = [];
	}
	get inboundTransports() {
		return this._inboundTransports;
	}
	registerInboundTransport(inboundTransport) {
		this._inboundTransports.push(inboundTransport);
	}
	async unregisterInboundTransport(inboundTransport) {
		this._inboundTransports = this._inboundTransports.filter((transport) => transport !== inboundTransport);
		await inboundTransport.stop();
	}
	/**
	* Receive and handle an inbound DIDComm message. It will determine the agent context, decrypt the message, transform it
	* to it's corresponding message class and finally dispatch it to the dispatcher.
	*
	* @param inboundMessage the message to receive and handle
	*/
	async receiveMessage(inboundMessage, { session, connection, contextCorrelationId, receivedAt } = {}) {
		this.logger.debug("Agent received message");
		const agentContext = await this.agentContextProvider.getContextForInboundMessage(inboundMessage, { contextCorrelationId });
		try {
			if (this.isEncryptedMessage(inboundMessage)) await this.receiveEncryptedMessage(agentContext, inboundMessage, session, receivedAt);
			else if (this.isPlaintextMessage(inboundMessage)) await this.receivePlaintextMessage(agentContext, inboundMessage, connection, receivedAt);
			else throw new __credo_ts_core.CredoError("Unable to parse incoming message: unrecognized format");
		} finally {
			await agentContext.endSession();
		}
	}
	async receivePlaintextMessage(agentContext, plaintextMessage, connection, receivedAt) {
		const messageContext = new require_DidCommInboundMessageContext.DidCommInboundMessageContext(await this.transformAndValidate(agentContext, plaintextMessage), {
			connection,
			agentContext,
			receivedAt
		});
		await this.dispatcher.dispatch(messageContext);
	}
	async receiveEncryptedMessage(agentContext, encryptedMessage, session, receivedAt) {
		const decryptedMessage = await this.decryptMessage(agentContext, encryptedMessage);
		const { plaintextMessage, senderKey, recipientKey } = decryptedMessage;
		this.logger.info(`Received message with type '${plaintextMessage["@type"]}', recipient key ${recipientKey?.fingerprint} and sender key ${senderKey?.fingerprint}`, plaintextMessage);
		const connection = await this.findConnectionByMessageKeys(agentContext, decryptedMessage);
		const message = await this.transformAndValidate(agentContext, plaintextMessage, connection);
		const messageContext = new require_DidCommInboundMessageContext.DidCommInboundMessageContext(message, {
			connection: connection?.isReady ? connection : void 0,
			senderKey,
			recipientKey,
			agentContext,
			receivedAt,
			encryptedMessage
		});
		if (senderKey && recipientKey && message.hasAnyReturnRoute() && session) {
			this.logger.debug(`Storing session for inbound message '${message.id}'`);
			session.keys = {
				recipientKeys: [senderKey],
				routingKeys: [],
				senderKey: recipientKey
			};
			session.inboundMessage = message;
			session.connectionId = connection?.id;
			messageContext.sessionId = session.id;
			this.transportService.saveSession(session);
		} else if (session) await session.close();
		await this.dispatcher.dispatch(messageContext);
	}
	/**
	* Decrypt a message using the envelope service.
	*
	* @param message the received inbound message to decrypt
	*/
	async decryptMessage(agentContext, message) {
		try {
			return await this.envelopeService.unpackMessage(agentContext, message);
		} catch (error) {
			this.logger.error("Error while decrypting message", {
				error,
				encryptedMessage: message,
				errorMessage: error instanceof Error ? error.message : error
			});
			throw error;
		}
	}
	isPlaintextMessage(message) {
		if (typeof message !== "object" || message == null) return false;
		return "@type" in message;
	}
	isEncryptedMessage(message) {
		return require_JWE.isValidJweStructure(message);
	}
	async transformAndValidate(agentContext, plaintextMessage, connection) {
		let message;
		try {
			message = await this.transformMessage(plaintextMessage);
		} catch (error) {
			if (connection) await this.sendProblemReportMessage(agentContext, error.message, connection, plaintextMessage);
			throw error;
		}
		return message;
	}
	async findConnectionByMessageKeys(agentContext, { recipientKey, senderKey }) {
		if (!recipientKey || !senderKey) return null;
		return this.connectionService.findByKeys(agentContext, {
			senderKey,
			recipientKey
		});
	}
	/**
	* Transform an plaintext DIDComm message into it's corresponding message class. Will look at all message types in the registered handlers.
	*
	* @param message the plaintext message for which to transform the message in to a class instance
	*/
	async transformMessage(message) {
		require_messageType.replaceLegacyDidSovPrefixOnMessage(message);
		const messageType = message["@type"];
		const MessageClass = this.messageHandlerRegistry.getMessageClassForMessageType(messageType) ?? require_DidCommMessage.DidCommMessage;
		let messageTransformed;
		try {
			messageTransformed = __credo_ts_core.JsonTransformer.fromJSON(message, MessageClass);
		} catch (error) {
			this.logger.error(`Error validating message ${message["@type"]}`, {
				errors: error,
				message: JSON.stringify(message)
			});
			throw new require_DidCommProblemReportError.DidCommProblemReportError(`Error validating message ${message["@type"]}`, { problemCode: require_DidCommProblemReportReason.DidCommProblemReportReason.MessageParseFailure });
		}
		return messageTransformed;
	}
	/**
	* Send the problem report message (https://didcomm.org/notification/1.0/problem-report) to the recipient.
	* @param message error message to send
	* @param connection connection to send the message to
	* @param plaintextMessage received inbound message
	*/
	async sendProblemReportMessage(agentContext, message, connection, plaintextMessage) {
		if (require_messageType.canHandleMessageType(require_DidCommProblemReportMessage.DidCommProblemReportMessage, require_messageType.parseMessageType(plaintextMessage["@type"]))) throw new __credo_ts_core.CredoError(`Not sending problem report in response to problem report: ${message}`);
		const problemReportMessage = new require_DidCommProblemReportMessage.DidCommProblemReportMessage({ description: {
			en: message,
			code: require_DidCommProblemReportReason.DidCommProblemReportReason.MessageParseFailure
		} });
		problemReportMessage.setThread({ parentThreadId: plaintextMessage["@id"] });
		const outboundMessageContext = new require_DidCommOutboundMessageContext.DidCommOutboundMessageContext(problemReportMessage, {
			agentContext,
			connection
		});
		if (outboundMessageContext) await this.messageSender.sendMessage(outboundMessageContext);
	}
};
DidCommMessageReceiver = require_decorate.__decorate([
	(0, __credo_ts_core.injectable)(),
	require_decorateParam.__decorateParam(6, (0, __credo_ts_core.inject)(__credo_ts_core.InjectionSymbols.AgentContextProvider)),
	require_decorateParam.__decorateParam(7, (0, __credo_ts_core.inject)(__credo_ts_core.InjectionSymbols.Logger)),
	require_decorateMetadata.__decorateMetadata("design:paramtypes", [
		typeof (_ref = typeof require_DidCommEnvelopeService.DidCommEnvelopeService !== "undefined" && require_DidCommEnvelopeService.DidCommEnvelopeService) === "function" ? _ref : Object,
		typeof (_ref2 = typeof require_DidCommTransportService.DidCommTransportService !== "undefined" && require_DidCommTransportService.DidCommTransportService) === "function" ? _ref2 : Object,
		typeof (_ref3 = typeof require_DidCommMessageSender.DidCommMessageSender !== "undefined" && require_DidCommMessageSender.DidCommMessageSender) === "function" ? _ref3 : Object,
		typeof (_ref4 = typeof require_DidCommConnectionService.DidCommConnectionService !== "undefined" && require_DidCommConnectionService.DidCommConnectionService) === "function" ? _ref4 : Object,
		typeof (_ref5 = typeof require_DidCommDispatcher.DidCommDispatcher !== "undefined" && require_DidCommDispatcher.DidCommDispatcher) === "function" ? _ref5 : Object,
		typeof (_ref6 = typeof require_DidCommMessageHandlerRegistry.DidCommMessageHandlerRegistry !== "undefined" && require_DidCommMessageHandlerRegistry.DidCommMessageHandlerRegistry) === "function" ? _ref6 : Object,
		Object,
		Object
	])
], DidCommMessageReceiver);

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