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 { canHandleMessageType, parseMessageType, replaceLegacyDidSovPrefixOnMessage } from "./util/messageType.mjs";
import { DidCommMessage } from "./DidCommMessage.mjs";
import { DidCommProblemReportMessage } from "./messages/problem-reports/DidCommProblemReportMessage.mjs";
import { DidCommProblemReportError } from "./errors/problem-reports/DidCommProblemReportError.mjs";
import "./errors/index.mjs";
import "./messages/index.mjs";
import { DidCommProblemReportReason } from "./models/problem-reports/DidCommProblemReportReason.mjs";
import { DidCommInboundMessageContext } from "./models/DidCommInboundMessageContext.mjs";
import { DidCommOutboundMessageContext } from "./models/DidCommOutboundMessageContext.mjs";
import "./models/index.mjs";
import { isValidJweStructure } from "./util/JWE.mjs";
import { DidCommTransportService } from "./DidCommTransportService.mjs";
import { __decorateParam } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.mjs";
import { DidCommConnectionService } from "./modules/connections/services/DidCommConnectionService.mjs";
import { DidCommEnvelopeService } from "./DidCommEnvelopeService.mjs";
import { DidCommMessageSender } from "./DidCommMessageSender.mjs";
import "./modules/connections/services/index.mjs";
import { DidCommMessageHandlerRegistry } from "./DidCommMessageHandlerRegistry.mjs";
import { DidCommDispatcher } from "./DidCommDispatcher.mjs";
import { CredoError, InjectionSymbols, JsonTransformer, inject, injectable } from "@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 CredoError("Unable to parse incoming message: unrecognized format");
		} finally {
			await agentContext.endSession();
		}
	}
	async receivePlaintextMessage(agentContext, plaintextMessage, connection, receivedAt) {
		const messageContext = new 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 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 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) {
		replaceLegacyDidSovPrefixOnMessage(message);
		const messageType = message["@type"];
		const MessageClass = this.messageHandlerRegistry.getMessageClassForMessageType(messageType) ?? DidCommMessage;
		let messageTransformed;
		try {
			messageTransformed = JsonTransformer.fromJSON(message, MessageClass);
		} catch (error) {
			this.logger.error(`Error validating message ${message["@type"]}`, {
				errors: error,
				message: JSON.stringify(message)
			});
			throw new DidCommProblemReportError(`Error validating message ${message["@type"]}`, { problemCode: 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 (canHandleMessageType(DidCommProblemReportMessage, parseMessageType(plaintextMessage["@type"]))) throw new CredoError(`Not sending problem report in response to problem report: ${message}`);
		const problemReportMessage = new DidCommProblemReportMessage({ description: {
			en: message,
			code: DidCommProblemReportReason.MessageParseFailure
		} });
		problemReportMessage.setThread({ parentThreadId: plaintextMessage["@id"] });
		const outboundMessageContext = new DidCommOutboundMessageContext(problemReportMessage, {
			agentContext,
			connection
		});
		if (outboundMessageContext) await this.messageSender.sendMessage(outboundMessageContext);
	}
};
DidCommMessageReceiver = __decorate([
	injectable(),
	__decorateParam(6, inject(InjectionSymbols.AgentContextProvider)),
	__decorateParam(7, inject(InjectionSymbols.Logger)),
	__decorateMetadata("design:paramtypes", [
		typeof (_ref = typeof DidCommEnvelopeService !== "undefined" && DidCommEnvelopeService) === "function" ? _ref : Object,
		typeof (_ref2 = typeof DidCommTransportService !== "undefined" && DidCommTransportService) === "function" ? _ref2 : Object,
		typeof (_ref3 = typeof DidCommMessageSender !== "undefined" && DidCommMessageSender) === "function" ? _ref3 : Object,
		typeof (_ref4 = typeof DidCommConnectionService !== "undefined" && DidCommConnectionService) === "function" ? _ref4 : Object,
		typeof (_ref5 = typeof DidCommDispatcher !== "undefined" && DidCommDispatcher) === "function" ? _ref5 : Object,
		typeof (_ref6 = typeof DidCommMessageHandlerRegistry !== "undefined" && DidCommMessageHandlerRegistry) === "function" ? _ref6 : Object,
		Object,
		Object
	])
], DidCommMessageReceiver);

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