

import { isKnownJwaSignatureAlgorithm } from "../kms/jwk/jwa.mjs";
import { TypedArrayEncoder } from "../../utils/TypedArrayEncoder.mjs";
import "../../utils/index.mjs";
import { PublicJwk } from "../kms/jwk/PublicJwk.mjs";
import "../kms/index.mjs";
import { X509Certificate } from "../x509/X509Certificate.mjs";
import { X509ModuleConfig } from "../x509/X509ModuleConfig.mjs";
import "../x509/index.mjs";
import { ClaimFormat } from "../vc/models/ClaimFormat.mjs";
import "../vc/index.mjs";
import { getMdocContext } from "./MdocContext.mjs";
import { MdocError } from "./MdocError.mjs";
import { isMdocSupportedSignatureAlgorithm, mdocSupporteSignatureAlgorithms } from "./mdocSupportedAlgs.mjs";
import { COSEKey, DeviceSignedDocument, Document, Verifier, cborEncode, parseDeviceSigned, parseIssuerSigned } from "@animo-id/mdoc";

//#region src/modules/mdoc/Mdoc.ts
/**
* This class represents a IssuerSigned Mdoc Document,
* which are the actual credentials being issued to holders.
*/
var Mdoc = class Mdoc {
	constructor(issuerSignedDocument) {
		this.issuerSignedDocument = issuerSignedDocument;
		const issuerSigned = issuerSignedDocument.prepare().get("issuerSigned");
		this.base64Url = TypedArrayEncoder.toBase64URL(cborEncode(issuerSigned));
	}
	/**
	* claim format is convenience method added to all credential instances
	*/
	get claimFormat() {
		return ClaimFormat.MsoMdoc;
	}
	/**
	* Encoded is convenience method added to all credential instances
	*/
	get encoded() {
		return this.base64Url;
	}
	/**
	* Get the device key to which the mdoc is bound
	*/
	get deviceKey() {
		const deviceKeyRaw = this.issuerSignedDocument.issuerSigned.issuerAuth.decodedPayload.deviceKeyInfo?.deviceKey;
		if (!deviceKeyRaw) return null;
		return PublicJwk.fromUnknown(COSEKey.import(deviceKeyRaw).toJWK());
	}
	static fromBase64Url(mdocBase64Url, expectedDocType) {
		return new Mdoc(parseIssuerSigned(TypedArrayEncoder.fromBase64(mdocBase64Url), expectedDocType));
	}
	static fromIssuerSignedDocument(issuerSignedBase64Url, expectedDocType) {
		return new Mdoc(parseIssuerSigned(TypedArrayEncoder.fromBase64(issuerSignedBase64Url), expectedDocType));
	}
	static fromDeviceSignedDocument(issuerSignedBase64Url, deviceSignedBase64Url, expectedDocType) {
		return new Mdoc(parseDeviceSigned(TypedArrayEncoder.fromBase64(deviceSignedBase64Url), TypedArrayEncoder.fromBase64(issuerSignedBase64Url), expectedDocType));
	}
	get docType() {
		return this.issuerSignedDocument.docType;
	}
	get alg() {
		const algName = this.issuerSignedDocument.issuerSigned.issuerAuth.algName;
		if (!algName) throw new MdocError("Cannot extract the signature algorithm from the mdoc.");
		if (isKnownJwaSignatureAlgorithm(algName)) return algName;
		throw new MdocError(`Cannot parse mdoc. The signature algorithm '${algName}' is not supported.`);
	}
	get validityInfo() {
		return this.issuerSignedDocument.issuerSigned.issuerAuth.decodedPayload.validityInfo;
	}
	get deviceSignedNamespaces() {
		if (this.issuerSignedDocument instanceof DeviceSignedDocument === false) return null;
		return Object.fromEntries(Array.from(this.issuerSignedDocument.allDeviceSignedNamespaces.entries()).map(([namespace, value]) => [namespace, Object.fromEntries(Array.from(value.entries()))]));
	}
	get issuerSignedCertificateChain() {
		return this.issuerSignedDocument.issuerSigned.issuerAuth.certificateChain;
	}
	get signingCertificate() {
		return this.issuerSignedDocument.issuerSigned.issuerAuth.certificate;
	}
	get issuerSignedNamespaces() {
		return Object.fromEntries(Array.from(this.issuerSignedDocument.allIssuerSignedNamespaces.entries()).map(([namespace, value]) => [namespace, Object.fromEntries(Array.from(value.entries()))]));
	}
	static async sign(agentContext, options) {
		const { docType, validityInfo, namespaces, holderKey, issuerCertificate } = options;
		const mdocContext = getMdocContext(agentContext);
		const document = new Document(docType, mdocContext).useDigestAlgorithm("SHA-256").addValidityInfo(validityInfo).addDeviceKeyInfo({ deviceKey: holderKey.toJson() });
		for (const [namespace, namespaceRecord] of Object.entries(namespaces)) document.addIssuerNameSpace(namespace, namespaceRecord);
		const issuerKey = issuerCertificate.publicJwk;
		const alg = issuerKey.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm);
		if (!alg) throw new MdocError(`Unable to create sign mdoc. No supported signature algorithm found to sign mdoc for jwk with key ${issuerKey.jwkTypehumanDescription}. Key supports algs ${issuerKey.supportedSignatureAlgorithms.join(", ")}. mdoc supports algs ${mdocSupporteSignatureAlgorithms.join(", ")}`);
		return new Mdoc(await document.sign({
			issuerPrivateKey: issuerKey.toJson(),
			alg,
			issuerCertificate: issuerCertificate.rawCertificate
		}, mdocContext));
	}
	async verify(agentContext, options) {
		const x509ModuleConfig = agentContext.dependencyManager.resolve(X509ModuleConfig);
		const certificateChain = this.issuerSignedDocument.issuerSigned.issuerAuth.certificateChain.map((certificate) => X509Certificate.fromRawCertificate(certificate));
		let trustedCertificates = options?.trustedCertificates;
		if (!trustedCertificates) trustedCertificates = await x509ModuleConfig.getTrustedCertificatesForVerification?.(agentContext, {
			verification: {
				type: "credential",
				credential: this
			},
			certificateChain
		}) ?? x509ModuleConfig.trustedCertificates;
		if (!trustedCertificates) throw new MdocError("No trusted certificates found. Cannot verify mdoc.");
		const mdocContext = getMdocContext(agentContext);
		try {
			const verifier = new Verifier();
			await verifier.verifyIssuerSignature({
				trustedCertificates: trustedCertificates.map((cert) => X509Certificate.fromEncodedCertificate(cert).rawCertificate),
				issuerAuth: this.issuerSignedDocument.issuerSigned.issuerAuth,
				disableCertificateChainValidation: false,
				now: options?.now
			}, mdocContext);
			await verifier.verifyData({ mdoc: this.issuerSignedDocument }, mdocContext);
			return { isValid: true };
		} catch (error) {
			return {
				isValid: false,
				error: error.message
			};
		}
	}
	toJSON() {
		return this.base64Url;
	}
	toString() {
		return this.base64Url;
	}
};

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