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 { AckStatus } from "../../../messages/common/DidCommAckMessage.mjs";
import "../../../messages/index.mjs";
import { DidCommOutboundMessageContext } from "../../../models/DidCommOutboundMessageContext.mjs";
import "../../../models/index.mjs";
import { DidCommDidRotateProblemReportMessage } from "../messages/DidCommDidRotateProblemReportMessage.mjs";
import { DidCommDidRotateMessage } from "../messages/DidCommDidRotateMessage.mjs";
import { DidCommDidRotateAckMessage } from "../messages/DidCommDidRotateAckMessage.mjs";
import { DidCommHangupMessage } from "../messages/DidCommHangupMessage.mjs";
import "../messages/index.mjs";
import { __decorateParam } from "../../../../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.mjs";
import { createPeerDidFromServices, routingToServices } from "./helpers.mjs";
import { DidCommConnectionEventTypes } from "../DidCommConnectionEvents.mjs";
import { DidCommConnectionService } from "./DidCommConnectionService.mjs";
import { DidCommConnectionMetadataKeys } from "../repository/DidCommConnectionMetadataTypes.mjs";
import { getMediationRecordForDidDocument } from "../../routing/services/helpers.mjs";
import { DidCommConnectionsModuleConfig } from "../DidCommConnectionsModuleConfig.mjs";
import { CredoError, DidRepository, DidResolverService, DidsApi, EventEmitter, InjectionSymbols, PeerDidNumAlgo, getAlternativeDidsForPeerDid, getNumAlgoFromPeerDid, inject, injectable, isValidPeerDid } from "@credo-ts/core";

//#region ../didcomm/src/modules/connections/services/DidCommDidRotateService.ts
var _ref, _ref2;
let DidCommDidRotateService = class DidCommDidRotateService$1 {
	constructor(didResolverService, logger, eventEmitter) {
		this.didResolverService = didResolverService;
		this.logger = logger;
		this.eventEmitter = eventEmitter;
	}
	async createRotate(agentContext, options) {
		const { connection, toDid, routing } = options;
		const config = agentContext.resolve(DidCommConnectionsModuleConfig);
		const dids = agentContext.resolve(DidsApi);
		if (connection.metadata.get(DidCommConnectionMetadataKeys.DidRotate)) throw new CredoError(`There is already an existing opened did rotation flow for connection id ${connection.id}`);
		let resolvedDid;
		let mediatorId;
		if (toDid) {
			resolvedDid = await dids.resolveCreatedDidDocumentWithKeys(toDid);
			mediatorId = (await getMediationRecordForDidDocument(agentContext, resolvedDid.didDocument))?.id;
		} else {
			if (!routing) throw new CredoError("Routing configuration must be defined when rotating to a new peer did");
			resolvedDid = await createPeerDidFromServices(agentContext, routingToServices(routing), config.peerNumAlgoForDidRotation);
			mediatorId = routing.mediatorId;
		}
		const message = new DidCommDidRotateMessage({ toDid: resolvedDid.didDocument.id });
		connection.metadata.set(DidCommConnectionMetadataKeys.DidRotate, {
			threadId: message.threadId,
			did: resolvedDid.didDocument.id,
			mediatorId
		});
		await agentContext.resolve(DidCommConnectionService).update(agentContext, connection);
		return message;
	}
	async createHangup(agentContext, options) {
		const { connection } = options;
		const message = new DidCommHangupMessage({});
		if (connection.did) connection.previousDids = [...connection.previousDids, connection.did];
		connection.did = void 0;
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
		return message;
	}
	/**
	* Process a Hangup message and mark connection's theirDid as undefined so it is effectively terminated.
	* Connection Record itself is not deleted (TODO: config parameter to automatically do so)
	*
	* Its previous did will be stored in record in order to be able to recognize any message received
	* afterwards.
	*
	* @param messageContext
	*/
	async processHangup(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const { agentContext } = messageContext;
		if (connection.theirDid) connection.previousTheirDids = [...connection.previousTheirDids, connection.theirDid];
		const previousTheirDid = connection.theirDid;
		connection.theirDid = void 0;
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
		this.emitDidRotatedEvent(agentContext, connection, { previousTheirDid });
	}
	/**
	* Process an incoming DID Rotate message and update connection if success. Any acknowledge
	* or problem report will be sent to the prior DID, so the created context will take former
	* connection record data
	*
	* @param paramInboundDidCommMessageContext
	* @param connection
	* @returns
	*/
	async processRotate(messageContext) {
		const connection = messageContext.assertReadyConnection();
		const { message, agentContext } = messageContext;
		const newDid = message.toDid;
		if (isValidPeerDid(newDid) && getNumAlgoFromPeerDid(newDid) === PeerDidNumAlgo.GenesisDoc) {
			this.logger.error(`Unable to resolve DID Document for '${newDid}`);
			return new DidCommOutboundMessageContext(new DidCommDidRotateProblemReportMessage({ description: {
				en: "DID Method Unsupported",
				code: "e.did.method_unsupported"
			} }), {
				agentContext,
				connection
			});
		}
		const didDocument = (await this.didResolverService.resolve(agentContext, newDid)).didDocument;
		if (!didDocument) {
			this.logger.error(`Unable to resolve DID Document for '${newDid}`);
			return new DidCommOutboundMessageContext(new DidCommDidRotateProblemReportMessage({ description: {
				en: "DID Unresolvable",
				code: "e.did.unresolvable"
			} }), {
				agentContext,
				connection
			});
		}
		if (!didDocument.didCommServices) return new DidCommOutboundMessageContext(new DidCommDidRotateProblemReportMessage({ description: {
			en: "DID Document Unsupported",
			code: "e.did.doc_unsupported"
		} }), {
			agentContext,
			connection
		});
		const outboundMessageContext = new DidCommOutboundMessageContext(new DidCommDidRotateAckMessage({
			threadId: message.threadId,
			status: AckStatus.OK
		}), {
			agentContext,
			connection: connection.clone()
		});
		await agentContext.dependencyManager.resolve(DidRepository).storeReceivedDid(agentContext, {
			did: didDocument.id,
			didDocument,
			tags: { alternativeDids: isValidPeerDid(didDocument.id) ? getAlternativeDidsForPeerDid(didDocument.id) : void 0 }
		});
		if (connection.theirDid) connection.previousTheirDids = [...connection.previousTheirDids, connection.theirDid];
		const previousTheirDid = connection.theirDid;
		connection.theirDid = newDid;
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
		this.emitDidRotatedEvent(agentContext, connection, { previousTheirDid });
		return outboundMessageContext;
	}
	async processRotateAck(inboundMessage) {
		const { agentContext, message } = inboundMessage;
		const connection = inboundMessage.assertReadyConnection();
		const didRotateMetadata = connection.metadata.get(DidCommConnectionMetadataKeys.DidRotate);
		if (!didRotateMetadata) throw new CredoError(`No did rotation data found for connection with id '${connection.id}'`);
		if (didRotateMetadata.threadId !== message.threadId) throw new CredoError(`Existing did rotation flow thread id '${didRotateMetadata.threadId} does not match incoming message'`);
		if (connection.did) connection.previousDids = [...connection.previousDids, connection.did];
		const previousOurDid = connection.did;
		connection.did = didRotateMetadata.did;
		connection.mediatorId = didRotateMetadata.mediatorId;
		connection.metadata.delete(DidCommConnectionMetadataKeys.DidRotate);
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
		this.emitDidRotatedEvent(agentContext, connection, { previousOurDid });
	}
	/**
	* Process a problem report related to did rotate protocol, by simply deleting any temporary metadata.
	*
	* No specific event is thrown other than generic message processing
	*DidCommInboundMessageContext
	* @param messageContext
	*/
	async processProblemReport(messageContext) {
		const { message, agentContext } = messageContext;
		const connection = messageContext.assertReadyConnection();
		this.logger.debug(`Processing problem report with id ${message.id}`);
		if (!connection.metadata.get(DidCommConnectionMetadataKeys.DidRotate)) throw new CredoError(`No did rotation data found for connection with id '${connection.id}'`);
		connection.metadata.delete(DidCommConnectionMetadataKeys.DidRotate);
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
	}
	async clearDidRotationData(agentContext, connection) {
		if (!connection.metadata.get(DidCommConnectionMetadataKeys.DidRotate)) throw new CredoError(`No did rotation data found for connection with id '${connection.id}'`);
		connection.metadata.delete(DidCommConnectionMetadataKeys.DidRotate);
		await agentContext.dependencyManager.resolve(DidCommConnectionService).update(agentContext, connection);
	}
	emitDidRotatedEvent(agentContext, connectionRecord, { previousOurDid, previousTheirDid }) {
		this.eventEmitter.emit(agentContext, {
			type: DidCommConnectionEventTypes.DidCommConnectionDidRotated,
			payload: {
				connectionRecord: connectionRecord.clone(),
				ourDid: previousOurDid && connectionRecord.did ? {
					from: previousOurDid,
					to: connectionRecord.did
				} : void 0,
				theirDid: previousTheirDid && connectionRecord.theirDid ? {
					from: previousTheirDid,
					to: connectionRecord.theirDid
				} : void 0
			}
		});
	}
};
DidCommDidRotateService = __decorate([
	injectable(),
	__decorateParam(1, inject(InjectionSymbols.Logger)),
	__decorateMetadata("design:paramtypes", [
		typeof (_ref = typeof DidResolverService !== "undefined" && DidResolverService) === "function" ? _ref : Object,
		Object,
		typeof (_ref2 = typeof EventEmitter !== "undefined" && EventEmitter) === "function" ? _ref2 : Object
	])
], DidCommDidRotateService);

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