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 { DidCommOutOfBandState } from "./domain/DidCommOutOfBandState.mjs";
import { DidCommDocumentService } from "../../services/DidCommDocumentService.mjs";
import "../../services/index.mjs";
import { getResolvedDidcommServiceWithSigningKeyId } from "../connections/services/helpers.mjs";
import { DidCommOutOfBandEventTypes } from "./domain/DidCommOutOfBandEvents.mjs";
import { DidCommOutOfBandRole } from "./domain/DidCommOutOfBandRole.mjs";
import { DidCommOutOfBandInvitation } from "./messages/DidCommOutOfBandInvitation.mjs";
import { DidCommHandshakeReuseAcceptedMessage } from "./messages/DidCommHandshakeReuseAcceptedMessage.mjs";
import { DidCommHandshakeReuseMessage } from "./messages/DidCommHandshakeReuseMessage.mjs";
import "./messages/index.mjs";
import { DidCommOutOfBandRecord } from "./repository/DidCommOutOfBandRecord.mjs";
import { DidCommOutOfBandRepository } from "./repository/DidCommOutOfBandRepository.mjs";
import "./repository/index.mjs";
import { CredoError, DidsApi, EventEmitter, injectable, parseDid } from "@credo-ts/core";

//#region ../didcomm/src/modules/oob/DidCommOutOfBandService.ts
var _ref, _ref2, _ref3;
let DidCommOutOfBandService = class DidCommOutOfBandService$1 {
	constructor(outOfBandRepository, eventEmitter, didCommDocumentService) {
		this.outOfBandRepository = outOfBandRepository;
		this.eventEmitter = eventEmitter;
		this.didCommDocumentService = didCommDocumentService;
	}
	/**
	* Creates an Out of Band record from a Connection/DIDExchange request started by using
	* a publicly resolvable DID this agent can control
	*/
	async createFromImplicitInvitation(agentContext, config) {
		const { did, threadId, handshakeProtocols, autoAcceptConnection, recipientKey } = config;
		const publicDid = parseDid(did);
		const [createdDid] = await agentContext.dependencyManager.resolve(DidsApi).getCreatedDids({ did: publicDid.did });
		if (!createdDid) throw new CredoError(`Referenced public did ${did} not found.`);
		const outOfBandInvitation = new DidCommOutOfBandInvitation({
			id: did,
			services: [did],
			handshakeProtocols
		});
		outOfBandInvitation.setThread({ threadId });
		const outOfBandRecord = new DidCommOutOfBandRecord({
			role: DidCommOutOfBandRole.Sender,
			state: DidCommOutOfBandState.AwaitResponse,
			reusable: true,
			autoAcceptConnection: autoAcceptConnection ?? false,
			outOfBandInvitation,
			tags: { recipientKeyFingerprints: [recipientKey.fingerprint] }
		});
		await this.save(agentContext, outOfBandRecord);
		this.emitStateChangedEvent(agentContext, outOfBandRecord, null);
		return outOfBandRecord;
	}
	async processHandshakeReuse(messageContext) {
		const reuseMessage = messageContext.message;
		const parentThreadId = reuseMessage.thread?.parentThreadId;
		if (!parentThreadId) throw new CredoError("handshake-reuse message must have a parent thread id");
		const outOfBandRecord = await this.findByCreatedInvitationId(messageContext.agentContext, parentThreadId);
		if (!outOfBandRecord) throw new CredoError("No out of band record found for handshake-reuse message");
		outOfBandRecord.assertRole(DidCommOutOfBandRole.Sender);
		outOfBandRecord.assertState(DidCommOutOfBandState.AwaitResponse);
		if ((outOfBandRecord.outOfBandInvitation.getRequests()?.length ?? 0) > 0) throw new CredoError("Handshake reuse should only be used when no requests are present");
		const reusedConnection = messageContext.assertReadyConnection();
		this.eventEmitter.emit(messageContext.agentContext, {
			type: DidCommOutOfBandEventTypes.HandshakeReused,
			payload: {
				reuseThreadId: reuseMessage.threadId,
				connectionRecord: reusedConnection,
				outOfBandRecord
			}
		});
		if (!outOfBandRecord.reusable) await this.updateState(messageContext.agentContext, outOfBandRecord, DidCommOutOfBandState.Done);
		return new DidCommHandshakeReuseAcceptedMessage({
			threadId: reuseMessage.threadId,
			parentThreadId
		});
	}
	async processHandshakeReuseAccepted(messageContext) {
		const reuseAcceptedMessage = messageContext.message;
		const parentThreadId = reuseAcceptedMessage.thread?.parentThreadId;
		if (!parentThreadId) throw new CredoError("handshake-reuse-accepted message must have a parent thread id");
		const outOfBandRecord = await this.findByReceivedInvitationId(messageContext.agentContext, parentThreadId);
		if (!outOfBandRecord) throw new CredoError("No out of band record found for handshake-reuse-accepted message");
		outOfBandRecord.assertRole(DidCommOutOfBandRole.Receiver);
		outOfBandRecord.assertState(DidCommOutOfBandState.PrepareResponse);
		const reusedConnection = messageContext.assertReadyConnection();
		if (outOfBandRecord.reuseConnectionId !== reusedConnection.id) throw new CredoError("handshake-reuse-accepted is not in response to a handshake-reuse message.");
		this.eventEmitter.emit(messageContext.agentContext, {
			type: DidCommOutOfBandEventTypes.HandshakeReused,
			payload: {
				reuseThreadId: reuseAcceptedMessage.threadId,
				connectionRecord: reusedConnection,
				outOfBandRecord
			}
		});
		await this.updateState(messageContext.agentContext, outOfBandRecord, DidCommOutOfBandState.Done);
	}
	async createHandShakeReuse(agentContext, outOfBandRecord, connectionRecord) {
		const reuseMessage = new DidCommHandshakeReuseMessage({ parentThreadId: outOfBandRecord.outOfBandInvitation.id });
		outOfBandRecord.reuseConnectionId = connectionRecord.id;
		await this.outOfBandRepository.update(agentContext, outOfBandRecord);
		return reuseMessage;
	}
	async save(agentContext, outOfBandRecord) {
		return this.outOfBandRepository.save(agentContext, outOfBandRecord);
	}
	async updateState(agentContext, outOfBandRecord, newState) {
		const previousState = outOfBandRecord.state;
		outOfBandRecord.state = newState;
		await this.outOfBandRepository.update(agentContext, outOfBandRecord);
		this.emitStateChangedEvent(agentContext, outOfBandRecord, previousState);
	}
	emitStateChangedEvent(agentContext, outOfBandRecord, previousState) {
		this.eventEmitter.emit(agentContext, {
			type: DidCommOutOfBandEventTypes.OutOfBandStateChanged,
			payload: {
				outOfBandRecord: outOfBandRecord.clone(),
				previousState
			}
		});
	}
	async findById(agentContext, outOfBandRecordId) {
		return this.outOfBandRepository.findById(agentContext, outOfBandRecordId);
	}
	async getById(agentContext, outOfBandRecordId) {
		return this.outOfBandRepository.getById(agentContext, outOfBandRecordId);
	}
	async findByReceivedInvitationId(agentContext, receivedInvitationId) {
		return this.outOfBandRepository.findSingleByQuery(agentContext, {
			invitationId: receivedInvitationId,
			role: DidCommOutOfBandRole.Receiver
		});
	}
	async findByCreatedInvitationId(agentContext, createdInvitationId, threadId) {
		return this.outOfBandRepository.findSingleByQuery(agentContext, {
			invitationId: createdInvitationId,
			role: DidCommOutOfBandRole.Sender,
			threadId
		});
	}
	async findCreatedByRecipientKey(agentContext, recipientKey) {
		return this.outOfBandRepository.findSingleByQuery(agentContext, {
			recipientKeyFingerprints: [recipientKey.fingerprint],
			role: DidCommOutOfBandRole.Sender
		});
	}
	async getAll(agentContext) {
		return this.outOfBandRepository.getAll(agentContext);
	}
	async findAllByQuery(agentContext, query, queryOptions) {
		return this.outOfBandRepository.findByQuery(agentContext, query, queryOptions);
	}
	async deleteById(agentContext, outOfBandId) {
		const outOfBandRecord = await this.getById(agentContext, outOfBandId);
		return this.outOfBandRepository.delete(agentContext, outOfBandRecord);
	}
	/**
	* Extract a resolved didcomm service from an out of band invitation.
	*
	* Currently the first service that can be resolved is returned.
	*/
	async getResolvedServiceForOutOfBandServices(agentContext, services, inlineServiceKeys) {
		for (const service of services) if (typeof service === "string") {
			const [didService] = await this.didCommDocumentService.resolveServicesFromDid(agentContext, service);
			if (didService) return didService;
		} else return getResolvedDidcommServiceWithSigningKeyId(service, inlineServiceKeys);
		throw new CredoError("Could not extract a service from the out of band invitation.");
	}
};
DidCommOutOfBandService = __decorate([injectable(), __decorateMetadata("design:paramtypes", [
	typeof (_ref = typeof DidCommOutOfBandRepository !== "undefined" && DidCommOutOfBandRepository) === "function" ? _ref : Object,
	typeof (_ref2 = typeof EventEmitter !== "undefined" && EventEmitter) === "function" ? _ref2 : Object,
	typeof (_ref3 = typeof DidCommDocumentService !== "undefined" && DidCommDocumentService) === "function" ? _ref3 : Object
])], DidCommOutOfBandService);

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