

const require_CredoError = require('../../error/CredoError.js');
require('../../error/index.js');
require('../../agent/index.js');
const require_array = require('../../utils/array.js');
const require_did = require('../../utils/did.js');
require('../../utils/index.js');
const require_PublicJwk = require('../kms/jwk/PublicJwk.js');
require('../kms/index.js');
const require_parse = require('../dids/domain/parse.js');
const require_keyDidMapping = require('../dids/domain/key-type/keyDidMapping.js');
const require_DidResolverService = require('../dids/services/DidResolverService.js');
const require_DidsApi = require('../dids/DidsApi.js');
require('../dids/index.js');
const require_W3cV2JwtVerifiableCredential = require('./jwt-vc/W3cV2JwtVerifiableCredential.js');
const require_W3cV2SdJwtVerifiableCredential = require('./sd-jwt-vc/W3cV2SdJwtVerifiableCredential.js');
const require_utils = require('../sd-jwt-vc/utils.js');
require('./sd-jwt-vc/index.js');
const require_W3cV2JwtVerifiablePresentation = require('./jwt-vc/W3cV2JwtVerifiablePresentation.js');
require('./jwt-vc/index.js');
require('./models/index.js');

//#region src/modules/vc/v2-jwt-utils.ts
async function validateAndResolveVerificationMethod(agentContext, verificationMethod, allowsPurposes) {
	if (!require_did.isDid(verificationMethod)) throw new require_CredoError.CredoError("Only did identifiers are supported as verification method");
	const parsedDid = require_parse.parseDid(verificationMethod);
	if (!parsedDid.fragment) throw new require_CredoError.CredoError(`didUrl '${parsedDid.didUrl}' does not contain a '#'. Unable to derive key from did document`);
	const { didDocument, keys } = await agentContext.resolve(require_DidsApi.DidsApi).resolveCreatedDidDocumentWithKeys(parsedDid.did);
	const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes);
	const publicJwk = require_keyDidMapping.getPublicJwkFromVerificationMethod(verificationMethodObject);
	publicJwk.keyId = keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ?? publicJwk.legacyKeyId;
	return publicJwk;
}
async function extractHolderFromPresentationCredentials(agentContext, presentation) {
	const credentials = require_array.asArray(presentation.verifiableCredential);
	if (credentials.length !== 1) throw new require_CredoError.CredoError("Only a single verifiable credential is supported in a presentation");
	const credential = credentials[0];
	let claims;
	if (credential.envelopedCredential instanceof require_W3cV2SdJwtVerifiableCredential.W3cV2SdJwtVerifiableCredential) claims = credential.envelopedCredential.sdJwt.prettyClaims;
	else claims = credential.envelopedCredential.jwt.payload.toJson();
	const holderBinding = require_utils.parseHolderBindingFromCredential(claims);
	if (!holderBinding) throw new require_CredoError.CredoError("No holder binding found in credential included in presentation");
	return await require_utils.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 require_W3cV2JwtVerifiableCredential.W3cV2JwtVerifiableCredential) {
		alg = credential.jwt.header.alg;
		kid = credential.jwt.header.kid;
		iss = credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId;
	} else if (credential instanceof require_W3cV2JwtVerifiablePresentation.W3cV2JwtVerifiablePresentation) {
		alg = credential.jwt.header.alg;
		kid = credential.jwt.header.kid;
		iss = credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId;
	} else if (credential instanceof require_W3cV2SdJwtVerifiableCredential.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(require_DidResolverService.DidResolverService);
	let verificationMethod;
	if (kid?.startsWith("#")) {
		if (!iss || !require_did.isDid(iss)) throw new require_CredoError.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 && require_did.isDid(kid)) {
		const didDocument = await didResolver.resolveDidDocument(agentContext, kid);
		verificationMethod = didDocument.dereferenceKey(kid, purpose);
		if (iss && didDocument.id !== iss) throw new require_CredoError.CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${iss}'`);
	} else {
		if (!iss) throw new require_CredoError.CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`);
		const jwkClass = require_PublicJwk.PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(alg);
		const supportedVerificationMethodTypes = require_keyDidMapping.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 require_CredoError.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 require_CredoError.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 require_CredoError.CredoError(`Verification method controller '${verificationMethod.controller}' does not match the signer '${iss}'`);
	return verificationMethod;
}

//#endregion
exports.extractHolderFromPresentationCredentials = extractHolderFromPresentationCredentials;
exports.getVerificationMethodForJwt = getVerificationMethodForJwt;
exports.validateAndResolveVerificationMethod = validateAndResolveVerificationMethod;