

import { CredoError } from "../../error/CredoError.mjs";
import "../../error/index.mjs";
import "../../agent/index.mjs";
import { asArray } from "../../utils/array.mjs";
import { isDid } from "../../utils/did.mjs";
import "../../utils/index.mjs";
import { PublicJwk } from "../kms/jwk/PublicJwk.mjs";
import "../kms/index.mjs";
import { getPublicJwkFromVerificationMethod, getSupportedVerificationMethodTypesForPublicJwk } from "../dids/domain/key-type/keyDidMapping.mjs";
import { parseDid } from "../dids/domain/parse.mjs";
import { DidResolverService } from "../dids/services/DidResolverService.mjs";
import { DidsApi } from "../dids/DidsApi.mjs";
import "../dids/index.mjs";
import { W3cV2JwtVerifiableCredential } from "./jwt-vc/W3cV2JwtVerifiableCredential.mjs";
import { W3cV2SdJwtVerifiableCredential } from "./sd-jwt-vc/W3cV2SdJwtVerifiableCredential.mjs";
import { W3cV2JwtVerifiablePresentation } from "./jwt-vc/W3cV2JwtVerifiablePresentation.mjs";
import { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from "../sd-jwt-vc/utils.mjs";
import "./sd-jwt-vc/index.mjs";
import "./jwt-vc/index.mjs";
import "./models/index.mjs";

//#region src/modules/vc/v2-jwt-utils.ts
async function validateAndResolveVerificationMethod(agentContext, verificationMethod, allowsPurposes) {
	if (!isDid(verificationMethod)) throw new CredoError("Only did identifiers are supported as verification method");
	const parsedDid = parseDid(verificationMethod);
	if (!parsedDid.fragment) throw new CredoError(`didUrl '${parsedDid.didUrl}' does not contain a '#'. Unable to derive key from did document`);
	const { didDocument, keys } = await agentContext.resolve(DidsApi).resolveCreatedDidDocumentWithKeys(parsedDid.did);
	const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes);
	const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodObject);
	publicJwk.keyId = keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ?? publicJwk.legacyKeyId;
	return publicJwk;
}
async function extractHolderFromPresentationCredentials(agentContext, presentation) {
	const credentials = asArray(presentation.verifiableCredential);
	if (credentials.length !== 1) throw new CredoError("Only a single verifiable credential is supported in a presentation");
	const credential = credentials[0];
	let claims;
	if (credential.envelopedCredential instanceof W3cV2SdJwtVerifiableCredential) claims = credential.envelopedCredential.sdJwt.prettyClaims;
	else claims = credential.envelopedCredential.jwt.payload.toJson();
	const holderBinding = parseHolderBindingFromCredential(claims);
	if (!holderBinding) throw new CredoError("No holder binding found in credential included in presentation");
	return await extractKeyFromHolderBinding(agentContext, holderBinding, true);
}
/**
* This method tries to find the verification method associated with the JWT credential or presentation.
* This verification method can then be used to verify the credential or presentation signature.
*/
async function getVerificationMethodForJwt(agentContext, credential, purpose) {
	let alg;
	let kid;
	let iss;
	if (credential instanceof W3cV2JwtVerifiableCredential) {
		alg = credential.jwt.header.alg;
		kid = credential.jwt.header.kid;
		iss = credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId;
	} else if (credential instanceof W3cV2JwtVerifiablePresentation) {
		alg = credential.jwt.header.alg;
		kid = credential.jwt.header.kid;
		iss = credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId;
	} else if (credential instanceof W3cV2SdJwtVerifiableCredential) {
		alg = credential.sdJwt.header.alg;
		kid = credential.sdJwt.header.kid;
		iss = credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId;
	} else {
		alg = credential.sdJwt.header.alg;
		kid = credential.sdJwt.header.kid;
		iss = credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId;
	}
	const didResolver = agentContext.dependencyManager.resolve(DidResolverService);
	let verificationMethod;
	if (kid?.startsWith("#")) {
		if (!iss || !isDid(iss)) throw new CredoError(`JWT 'iss' MUST be a did when 'kid' is a relative did url`);
		verificationMethod = (await didResolver.resolveDidDocument(agentContext, iss)).dereferenceKey(`${iss}${kid}`, purpose);
	} else if (kid && isDid(kid)) {
		const didDocument = await didResolver.resolveDidDocument(agentContext, kid);
		verificationMethod = didDocument.dereferenceKey(kid, purpose);
		if (iss && didDocument.id !== iss) throw new CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${iss}'`);
	} else {
		if (!iss) throw new CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`);
		const jwkClass = PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(alg);
		const supportedVerificationMethodTypes = getSupportedVerificationMethodTypesForPublicJwk(jwkClass);
		const didDocument = await didResolver.resolveDidDocument(agentContext, iss);
		const verificationMethods = didDocument.assertionMethod?.map((v) => typeof v === "string" ? didDocument.dereferenceVerificationMethod(v) : v).filter((v) => supportedVerificationMethodTypes.includes(v.type)) ?? [];
		if (verificationMethods.length === 0) throw new CredoError(`No verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`);
		if (verificationMethods.length > 1) throw new CredoError(`Multiple verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`);
		verificationMethod = verificationMethods[0];
	}
	if (iss && verificationMethod.controller !== iss) throw new CredoError(`Verification method controller '${verificationMethod.controller}' does not match the signer '${iss}'`);
	return verificationMethod;
}

//#endregion
export { extractHolderFromPresentationCredentials, getVerificationMethodForJwt, validateAndResolveVerificationMethod };
//# sourceMappingURL=v2-jwt-utils.mjs.map