import { EmbeddedAuthentication } from "../models/did/authentication/EmbeddedAuthentication.mjs";
import "../models/index.mjs";
import "../../oob/domain/OutOfBandDidCommService.mjs";
import { AgentContext, CredoError, DidCommV1Service, DidDocumentBuilder, DidDocumentRole, DidRepository, DidsApi, IndyAgentService, Kms, PeerDidNumAlgo, TypedArrayEncoder, createPeerDidDocumentFromServices, didDocumentJsonToNumAlgo1Did, getEd25519VerificationKey2018 } from "@credo-ts/core";

//#region ../didcomm/src/modules/connections/services/helpers.ts
function convertToNewDidDocument(didDoc, keys) {
	const didDocumentBuilder = new DidDocumentBuilder("");
	const oldIdNewIdMapping = {};
	for (const auth of didDoc.authentication) {
		const { publicKey: pk } = auth;
		if (pk.type === "Ed25519VerificationKey2018" && pk.value) {
			const ed25519VerificationMethod = convertPublicKeyToVerificationMethod(pk);
			const oldKeyId = normalizeId(pk.id);
			oldIdNewIdMapping[oldKeyId] = ed25519VerificationMethod.id;
			didDocumentBuilder.addAuthentication(ed25519VerificationMethod.id);
			if (auth instanceof EmbeddedAuthentication) didDocumentBuilder.addVerificationMethod(ed25519VerificationMethod);
		}
	}
	for (const pk of didDoc.publicKey) if (pk.type === "Ed25519VerificationKey2018" && pk.value) {
		const ed25519VerificationMethod = convertPublicKeyToVerificationMethod(pk);
		const oldKeyId = normalizeId(pk.id);
		oldIdNewIdMapping[oldKeyId] = ed25519VerificationMethod.id;
		didDocumentBuilder.addVerificationMethod(ed25519VerificationMethod);
	}
	for (let service of didDoc.didCommServices.reverse()) {
		const serviceId = normalizeId(service.id);
		if (service instanceof DidCommV1Service) service = new DidCommV1Service({
			id: serviceId,
			recipientKeys: service.recipientKeys.map((keyId) => {
				return oldIdNewIdMapping[normalizeId(keyId)];
			}),
			serviceEndpoint: service.serviceEndpoint,
			routingKeys: service.routingKeys,
			accept: service.accept,
			priority: service.priority
		});
		else if (service instanceof IndyAgentService) service = new IndyAgentService({
			id: serviceId,
			recipientKeys: service.recipientKeys,
			serviceEndpoint: service.serviceEndpoint,
			routingKeys: service.routingKeys,
			priority: service.priority
		});
		didDocumentBuilder.addService(service);
	}
	const didDocument = didDocumentBuilder.build();
	didDocument.id = didDocumentJsonToNumAlgo1Did(didDocument.toJSON());
	return {
		didDocument,
		keys: keys?.map((key) => ({
			...key,
			didDocumentRelativeKeyId: oldIdNewIdMapping[key.didDocumentRelativeKeyId]
		}))
	};
}
function normalizeId(fullId) {
	if (!fullId.includes("#") && fullId.includes(";")) {
		const [, ...ids$1] = fullId.split(";");
		return `#${ids$1.join(";")}`;
	}
	const [, ...ids] = fullId.split("#");
	return `#${ids.length ? ids.join("#") : fullId}`;
}
function convertPublicKeyToVerificationMethod(publicKey) {
	if (!publicKey.value) throw new CredoError(`Public key ${publicKey.id} does not have value property`);
	const publicKeyBase58 = publicKey.value;
	const ed25519Key = Kms.PublicJwk.fromPublicKey({
		kty: "OKP",
		crv: "Ed25519",
		publicKey: TypedArrayEncoder.fromBase58(publicKeyBase58)
	});
	return getEd25519VerificationKey2018({
		id: `#${publicKeyBase58.slice(0, 8)}`,
		publicJwk: ed25519Key,
		controller: "#id"
	});
}
function routingToServices(routing) {
	return routing.endpoints.map((endpoint, index) => ({
		id: `#inline-${index}`,
		serviceEndpoint: endpoint,
		recipientKeys: [routing.recipientKey],
		routingKeys: routing.routingKeys
	}));
}
/**
* Asserts that the keys we are going to use for creating a did document haven't already been used in another did document
* Due to how DIDComm v1 works (only reference the key not the did in encrypted message) we can't have multiple dids containing
* the same key as we won't know which did (and thus which connection) a message is intended for.
*/
async function assertNoCreatedDidExistsForKeys(agentContext, recipientKeys) {
	const didRepository = agentContext.dependencyManager.resolve(DidRepository);
	const recipientKeyFingerprints = recipientKeys.map((key) => key.fingerprint);
	const didsForServices = await didRepository.findByQuery(agentContext, {
		role: DidDocumentRole.Created,
		$or: recipientKeyFingerprints.map((fingerprint) => ({ recipientKeyFingerprints: [fingerprint] }))
	});
	if (didsForServices.length > 0) throw new CredoError(`A did already exists for some of the keys in the provided services. DIDComm v1 uses key based routing, and therefore it is not allowed to re-use the same key in multiple did documents for DIDComm. If you use the same 'routing' object for multiple invitations, instead provide an 'invitationDid' to the create invitation method. The following fingerprints are already in use: ${didsForServices.flatMap((did) => did.getTags().recipientKeyFingerprints ?? []).filter((f) => recipientKeyFingerprints.includes(f)).join(",")}`);
}
async function createPeerDidFromServices(agentContext, services, numAlgo) {
	const didsApi = agentContext.dependencyManager.resolve(DidsApi);
	const { didDocument, keys } = createPeerDidDocumentFromServices(services, true);
	await assertNoCreatedDidExistsForKeys(agentContext, didDocument.recipientKeys);
	const result = await didsApi.create({
		method: "peer",
		didDocument,
		options: {
			numAlgo,
			keys
		}
	});
	if (result.didState?.state !== "finished") throw new CredoError(`Did document creation failed: ${JSON.stringify(result.didState)}`);
	return didsApi.resolveCreatedDidDocumentWithKeys(result.didState.did);
}
function getResolvedDidcommServiceWithSigningKeyId(outOfBandDidcommService, inlineServiceKeys) {
	const resolvedService = outOfBandDidcommService.resolvedDidCommService;
	for (const recipientKey of resolvedService.recipientKeys) recipientKey.keyId = inlineServiceKeys?.find(({ recipientKeyFingerprint }) => recipientKeyFingerprint === recipientKey.fingerprint)?.kmsKeyId ?? recipientKey.legacyKeyId;
	return resolvedService;
}

//#endregion
export { assertNoCreatedDidExistsForKeys, convertToNewDidDocument, createPeerDidFromServices, getResolvedDidcommServiceWithSigningKeyId, routingToServices };
//# sourceMappingURL=helpers.mjs.map