

const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.js');
const require_TypedArrayEncoder = require('../../utils/TypedArrayEncoder.js');
require('../../utils/index.js');
require('../kms/index.js');
const require_uuid = require('../../utils/uuid.js');
const require_ClaimFormat = require('../vc/models/ClaimFormat.js');
require('../vc/index.js');
const require_MdocContext = require('./MdocContext.js');
const require_MdocError = require('./MdocError.js');
const require_mdocSupportedAlgs = require('./mdocSupportedAlgs.js');
const require_Mdoc = require('./Mdoc.js');
const require_mdocUtil = require('./mdocUtil.js');
let __animo_id_mdoc = require("@animo-id/mdoc");
__animo_id_mdoc = require_rolldown_runtime.__toESM(__animo_id_mdoc);

//#region src/modules/mdoc/MdocDeviceResponse.ts
var _MdocDeviceResponse;
var MdocDeviceResponse = class MdocDeviceResponse {
	constructor(base64Url, documents) {
		this.base64Url = base64Url;
		this.documents = documents;
	}
	/**
	* claim format is convenience method added to all credential instances
	*/
	get claimFormat() {
		return require_ClaimFormat.ClaimFormat.MsoMdoc;
	}
	/**
	* Encoded is convenience method added to all credential instances
	*/
	get encoded() {
		return this.base64Url;
	}
	/**
	* To support a single DeviceResponse with multiple documents in OpenID4VP
	*/
	splitIntoSingleDocumentResponses() {
		const deviceResponses = [];
		if (this.documents.length === 0) throw new require_MdocError.MdocError("mdoc device response does not contain any mdocs");
		for (const document of this.documents) {
			const deviceResponse = new __animo_id_mdoc.MDoc();
			deviceResponse.addDocument(document.issuerSignedDocument);
			deviceResponses.push(MdocDeviceResponse.fromDeviceResponse(deviceResponse));
		}
		return deviceResponses;
	}
	static fromDeviceResponse(mdoc) {
		const documents = mdoc.documents.map((doc) => {
			const prepared = doc.prepare();
			const docType = prepared.get("docType");
			const issuerSigned = (0, __animo_id_mdoc.cborEncode)(prepared.get("issuerSigned"));
			const deviceSigned = (0, __animo_id_mdoc.cborEncode)(prepared.get("deviceSigned"));
			return require_Mdoc.Mdoc.fromDeviceSignedDocument(require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(issuerSigned), require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(deviceSigned), docType);
		});
		return new MdocDeviceResponse(require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(mdoc.encode()), documents);
	}
	static fromBase64Url(base64Url) {
		const parsed = (0, __animo_id_mdoc.parseDeviceResponse)(require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(base64Url));
		if (parsed.status !== __animo_id_mdoc.MDocStatus.OK) throw new require_MdocError.MdocError("Parsing Mdoc Device Response failed.");
		return MdocDeviceResponse.fromDeviceResponse(parsed);
	}
	static assertMdocInputDescriptor(inputDescriptor) {
		if (!inputDescriptor.format || !inputDescriptor.format.mso_mdoc) throw new require_MdocError.MdocError(`Input descriptor must contain 'mso_mdoc' format property`);
		if (!inputDescriptor.format.mso_mdoc.alg) throw new require_MdocError.MdocError(`Input descriptor mso_mdoc must contain 'alg' property`);
		if (!inputDescriptor.constraints?.limit_disclosure || inputDescriptor.constraints.limit_disclosure !== "required") throw new require_MdocError.MdocError(`Input descriptor must contain 'limit_disclosure' constraints property which is set to required`);
		if (!inputDescriptor.constraints?.fields?.every((field) => field.intent_to_retain !== void 0)) throw new require_MdocError.MdocError(`Input descriptor must contain 'intent_to_retain' constraints property`);
		return {
			...inputDescriptor,
			format: { mso_mdoc: inputDescriptor.format.mso_mdoc },
			constraints: {
				...inputDescriptor.constraints,
				limit_disclosure: "required",
				fields: (inputDescriptor.constraints.fields ?? []).map((field) => {
					return {
						...field,
						intent_to_retain: field.intent_to_retain ?? false
					};
				})
			}
		};
	}
	static createPresentationSubmission(input) {
		const { id, presentationDefinition } = input;
		if (presentationDefinition.input_descriptors.length !== 1) throw new require_MdocError.MdocError("Currently Mdoc Presentation Submissions can only be created for a sigle input descriptor");
		return {
			id,
			definition_id: presentationDefinition.id,
			descriptor_map: [{
				id: presentationDefinition.input_descriptors[0].id,
				format: "mso_mdoc",
				path: "$"
			}]
		};
	}
	static limitDisclosureToInputDescriptor(options) {
		const { mdoc } = options;
		const inputDescriptor = MdocDeviceResponse.assertMdocInputDescriptor(options.inputDescriptor);
		const disclosure = (0, __animo_id_mdoc.limitDisclosureToInputDescriptor)((0, __animo_id_mdoc.parseIssuerSigned)(require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(mdoc.base64Url), mdoc.docType), inputDescriptor);
		return Object.fromEntries(Array.from(disclosure.entries()).map(([namespace, issuerSignedItem]) => {
			return [namespace, Object.fromEntries(issuerSignedItem.map((item) => [item.elementIdentifier, item.elementValue]))];
		}));
	}
	static async createPresentationDefinitionDeviceResponse(agentContext, options) {
		const presentationDefinition = MdocDeviceResponse.partitionPresentationDefinition(options.presentationDefinition).mdocPresentationDefinition;
		const docTypes = options.mdocs.map((i) => i.docType);
		const combinedDeviceResponseMdoc = new __animo_id_mdoc.MDoc();
		for (const document of options.mdocs) {
			const deviceKeyJwk = document.deviceKey;
			if (!deviceKeyJwk) throw new require_MdocError.MdocError(`Device key is missing in mdoc with doctype ${document.docType}`);
			if (!deviceKeyJwk.hasKeyId) deviceKeyJwk.keyId = deviceKeyJwk.legacyKeyId;
			const alg = MdocDeviceResponse.getAlgForDeviceKeyJwk(deviceKeyJwk);
			const presentationDefinitionForDocument = {
				...presentationDefinition,
				input_descriptors: presentationDefinition.input_descriptors.filter((inputDescriptor) => inputDescriptor.id === document.docType)
			};
			const mdocContext = require_MdocContext.getMdocContext(agentContext);
			const issuerSignedDocument = (0, __animo_id_mdoc.parseIssuerSigned)(require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(document.base64Url), document.docType);
			const deviceResponseBuilder = __animo_id_mdoc.DeviceResponse.from(new __animo_id_mdoc.MDoc([issuerSignedDocument])).usingPresentationDefinition(presentationDefinitionForDocument).authenticateWithSignature(deviceKeyJwk.toJson(), alg).usingSessionTranscriptBytes(await MdocDeviceResponse.getSessionTranscriptBytesForOptions(mdocContext, options.sessionTranscriptOptions));
			for (const [nameSpace, nameSpaceValue] of Object.entries(options.deviceNameSpaces ?? {})) deviceResponseBuilder.addDeviceNameSpace(nameSpace, nameSpaceValue);
			const deviceResponseMdoc = await deviceResponseBuilder.sign(mdocContext);
			combinedDeviceResponseMdoc.addDocument(deviceResponseMdoc.documents[0]);
		}
		return {
			deviceResponseBase64Url: require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(combinedDeviceResponseMdoc.encode()),
			presentationSubmission: MdocDeviceResponse.createPresentationSubmission({
				id: `MdocPresentationSubmission ${require_uuid.uuid()}`,
				presentationDefinition: {
					...presentationDefinition,
					input_descriptors: presentationDefinition.input_descriptors.filter((i) => docTypes.includes(i.id))
				}
			})
		};
	}
	static async createDeviceResponse(agentContext, options) {
		const combinedDeviceResponseMdoc = new __animo_id_mdoc.MDoc();
		for (const document of options.mdocs) {
			const deviceKeyJwk = document.deviceKey;
			if (!deviceKeyJwk) throw new require_MdocError.MdocError(`Device key is missing in mdoc with doctype ${document.docType}`);
			const alg = MdocDeviceResponse.getAlgForDeviceKeyJwk(deviceKeyJwk);
			if (!deviceKeyJwk.hasKeyId) deviceKeyJwk.keyId = deviceKeyJwk.legacyKeyId;
			const issuerSignedDocument = (0, __animo_id_mdoc.parseIssuerSigned)(require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(document.base64Url), document.docType);
			const deviceRequestForDocument = __animo_id_mdoc.DeviceRequest.from("1.0", options.documentRequests.filter((request) => request.docType === issuerSignedDocument.docType).map((request) => ({ itemsRequestData: {
				docType: request.docType,
				nameSpaces: require_mdocUtil.nameSpacesRecordToMap(request.nameSpaces)
			} })));
			const mdocContext = require_MdocContext.getMdocContext(agentContext);
			const deviceResponseBuilder = __animo_id_mdoc.DeviceResponse.from(new __animo_id_mdoc.MDoc([issuerSignedDocument])).authenticateWithSignature(deviceKeyJwk.toJson(), alg).usingDeviceRequest(deviceRequestForDocument).usingSessionTranscriptBytes(await MdocDeviceResponse.getSessionTranscriptBytesForOptions(mdocContext, options.sessionTranscriptOptions));
			for (const [nameSpace, nameSpaceValue] of Object.entries(options.deviceNameSpaces ?? {})) deviceResponseBuilder.addDeviceNameSpace(nameSpace, nameSpaceValue);
			const deviceResponseMdoc = await deviceResponseBuilder.sign(mdocContext);
			combinedDeviceResponseMdoc.addDocument(deviceResponseMdoc.documents[0]);
		}
		return combinedDeviceResponseMdoc.encode();
	}
	async verify(agentContext, options) {
		const verifier = new __animo_id_mdoc.Verifier();
		const mdocContext = require_MdocContext.getMdocContext(agentContext);
		(0, __animo_id_mdoc.defaultCallback)({
			status: this.documents.length > 0 ? "PASSED" : "FAILED",
			check: "Device Response must include at least one document.",
			category: "DOCUMENT_FORMAT"
		});
		const deviceResponse = (0, __animo_id_mdoc.parseDeviceResponse)(require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(this.base64Url));
		for (const documentIndex of this.documents.keys()) {
			const rawDocument = deviceResponse.documents[documentIndex];
			const document = this.documents[documentIndex];
			const verificationResult = await document.verify(agentContext, {
				now: options.now,
				trustedCertificates: options.trustedCertificates
			});
			if (!verificationResult.isValid) throw new require_MdocError.MdocError(`Mdoc at index ${documentIndex} is not valid. ${verificationResult.error}`);
			if (!(rawDocument instanceof __animo_id_mdoc.DeviceSignedDocument)) {
				(0, __animo_id_mdoc.defaultCallback)({
					status: "FAILED",
					category: "DEVICE_AUTH",
					check: `The document is not signed by the device. ${document.docType}`
				});
				continue;
			}
			await verifier.verifyDeviceSignature({
				sessionTranscriptBytes: await MdocDeviceResponse.getSessionTranscriptBytesForOptions(mdocContext, options.sessionTranscriptOptions),
				deviceSigned: rawDocument
			}, mdocContext);
		}
		if (deviceResponse.documentErrors.length > 1) throw new require_MdocError.MdocError("Device response verification failed.");
		if (deviceResponse.status !== __animo_id_mdoc.MDocStatus.OK) throw new require_MdocError.MdocError("Device response verification failed. An unknown error occurred.");
		return this.documents;
	}
	static async getSessionTranscriptBytesForOptions(context, options) {
		if (options.type === "sesionTranscriptBytes") return options.sessionTranscriptBytes;
		if (options.type === "openId4Vp") return (0, __animo_id_mdoc.cborEncode)(__animo_id_mdoc.DataItem.fromData([
			null,
			null,
			["OpenID4VPHandover", await context.crypto.digest({
				digestAlgorithm: "SHA-256",
				bytes: (0, __animo_id_mdoc.cborEncode)([
					options.clientId,
					options.verifierGeneratedNonce,
					options.encryptionJwk?.getJwkThumbprint("sha-256") ?? null,
					options.responseUri
				])
			})]
		]));
		if (options.type === "openId4VpDraft18") return await __animo_id_mdoc.DeviceResponse.calculateSessionTranscriptBytesForOID4VP({
			...options,
			context
		});
		if (options.type === "openId4VpDcApi") return (0, __animo_id_mdoc.cborEncode)(__animo_id_mdoc.DataItem.fromData([
			null,
			null,
			["OpenID4VPDCAPIHandover", await context.crypto.digest({
				digestAlgorithm: "SHA-256",
				bytes: (0, __animo_id_mdoc.cborEncode)([
					options.origin,
					options.verifierGeneratedNonce,
					options.encryptionJwk?.getJwkThumbprint("sha-256") ?? null
				])
			})]
		]));
		if (options.type === "openId4VpDcApiDraft24") return await __animo_id_mdoc.DeviceResponse.calculateSessionTranscriptBytesForOID4VPDCApi({
			...options,
			context
		});
		throw new require_MdocError.MdocError("Unsupported session transcript option");
	}
	static getAlgForDeviceKeyJwk(jwk) {
		const signatureAlgorithm = jwk.supportedSignatureAlgorithms.find(require_mdocSupportedAlgs.isMdocSupportedSignatureAlgorithm);
		if (!signatureAlgorithm) throw new require_MdocError.MdocError(`Unable to create mdoc device response. No supported signature algorithm found to sign device response for jwk  ${jwk.jwkTypehumanDescription}. Key supports algs ${jwk.supportedSignatureAlgorithms.join(", ")}. mdoc supports algs ${require_mdocSupportedAlgs.mdocSupporteSignatureAlgorithms.join(", ")}`);
		return signatureAlgorithm;
	}
};
_MdocDeviceResponse = MdocDeviceResponse;
MdocDeviceResponse.partitionPresentationDefinition = (pd) => {
	const nonMdocPresentationDefinition = {
		...pd,
		input_descriptors: pd.input_descriptors.filter((id) => !Object.keys(id.format ?? {}).includes("mso_mdoc"))
	};
	return {
		mdocPresentationDefinition: {
			...pd,
			format: { mso_mdoc: pd.format?.mso_mdoc },
			input_descriptors: pd.input_descriptors.filter((id) => Object.keys(id.format ?? {}).includes("mso_mdoc")).map(_MdocDeviceResponse.assertMdocInputDescriptor)
		},
		nonMdocPresentationDefinition
	};
};

//#endregion
exports.MdocDeviceResponse = MdocDeviceResponse;