

const require_CredoError = require('../error/CredoError.js');
require('../agent/index.js');
const require_credentialUseTypes = require('./credentialUseTypes.js');
const require_W3cJsonLdVerifiableCredential = require('../modules/vc/data-integrity/models/W3cJsonLdVerifiableCredential.js');
const require_W3cV2JwtVerifiableCredential = require('../modules/vc/jwt-vc/W3cV2JwtVerifiableCredential.js');
const require_W3cV2SdJwtVerifiableCredential = require('../modules/vc/sd-jwt-vc/W3cV2SdJwtVerifiableCredential.js');
const require_W3cJwtVerifiableCredential = require('../modules/vc/jwt-vc/W3cJwtVerifiableCredential.js');
const require_W3cCredentialRecord = require('../modules/vc/repository/W3cCredentialRecord.js');
const require_W3cCredentialRepository = require('../modules/vc/repository/W3cCredentialRepository.js');
const require_W3cV2CredentialRecord = require('../modules/vc/repository/W3cV2CredentialRecord.js');
const require_W3cV2CredentialRepository = require('../modules/vc/repository/W3cV2CredentialRepository.js');
require('../modules/vc/repository/index.js');
require('../modules/vc/index.js');
const require_Mdoc = require('../modules/mdoc/Mdoc.js');
const require_MdocRecord = require('../modules/mdoc/repository/MdocRecord.js');
const require_MdocRepository = require('../modules/mdoc/repository/MdocRepository.js');
require('../modules/mdoc/repository/index.js');
const require_decodeSdJwtVc = require('../modules/sd-jwt-vc/decodeSdJwtVc.js');
const require_SdJwtVcRecord = require('../modules/sd-jwt-vc/repository/SdJwtVcRecord.js');
const require_SdJwtVcRepository = require('../modules/sd-jwt-vc/repository/SdJwtVcRepository.js');
require('../modules/sd-jwt-vc/repository/index.js');

//#region src/utils/credentialUse.ts
/**
* Checks whether an instance can be used from the provided record based on
* the required credential use mode.
*/
function canUseInstanceFromCredentialRecord({ credentialRecord, useMode }) {
	if (useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.First || useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.NewOrFirst || useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.NewIfReceivedInBatch && [require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUnused, require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUsed].includes(credentialRecord.multiInstanceState)) return true;
	return credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUnused;
}
/**
* Extract an instance with the correct kms key id from the credential instances
* on the record. Note that if an instance is extracted (that is not reused) it
* will remove the instance from the record, and the record should be updated in
* storage after usage.
*
* Note that the last credential instance is never removed from the record. So if the
* method indicates the last instance has been used, you should remove the credential
* from storage if you don't want it to be used anymore in the future.
*/
async function useInstanceFromCredentialRecord({ credentialRecord, useMode, agentContext, updateMode }) {
	let extractResult = extractInstanceAndUpdateRecord({
		credentialRecord,
		useMode
	});
	if ((!extractResult.isReused || extractResult.isLastNewInstance) && updateMode === require_credentialUseTypes.CredentialMultiInstanceUseUpdateMode.Update) await updateCredentialRecord(agentContext, credentialRecord);
	if ((!extractResult.isReused || extractResult.isLastNewInstance) && updateMode === require_credentialUseTypes.CredentialMultiInstanceUseUpdateMode.RefetchAndUpdateWithLock) await repositoryForRecord(agentContext, credentialRecord).updateByIdWithLock(agentContext, credentialRecord.id, async (freshCredentialRecord) => {
		extractResult = extractInstanceAndUpdateRecord({
			credentialRecord: freshCredentialRecord,
			useMode
		});
		return freshCredentialRecord;
	});
	let transformedCredentialInstance;
	if (credentialRecord instanceof require_MdocRecord.MdocRecord) {
		const { issuerSignedBase64Url, kmsKeyId } = extractResult.credentialInstance;
		transformedCredentialInstance = require_Mdoc.Mdoc.fromBase64Url(issuerSignedBase64Url);
		transformedCredentialInstance.deviceKeyId = kmsKeyId ?? transformedCredentialInstance.deviceKey.legacyKeyId;
	} else if (credentialRecord instanceof require_SdJwtVcRecord.SdJwtVcRecord) {
		const { compactSdJwtVc, kmsKeyId } = extractResult.credentialInstance;
		transformedCredentialInstance = {
			...require_decodeSdJwtVc.decodeSdJwtVc(compactSdJwtVc, credentialRecord.typeMetadata),
			kmsKeyId
		};
	} else if (credentialRecord instanceof require_W3cCredentialRecord.W3cCredentialRecord) {
		const { credential } = extractResult.credentialInstance;
		transformedCredentialInstance = typeof credential === "string" ? require_W3cJwtVerifiableCredential.W3cJwtVerifiableCredential.fromSerializedJwt(credential) : require_W3cJsonLdVerifiableCredential.W3cJsonLdVerifiableCredential.fromJson(credential);
	} else if (credentialRecord instanceof require_W3cV2CredentialRecord.W3cV2CredentialRecord) {
		const { credential } = extractResult.credentialInstance;
		transformedCredentialInstance = credential.includes("~") ? require_W3cV2SdJwtVerifiableCredential.W3cV2SdJwtVerifiableCredential.fromCompact(credential) : require_W3cV2JwtVerifiableCredential.W3cV2JwtVerifiableCredential.fromCompact(credential);
	} else throw new require_CredoError.CredoError("Unsupported record type");
	return {
		credentialInstance: transformedCredentialInstance,
		isReused: extractResult.isReused,
		isLastNewInstance: extractResult.isLastNewInstance
	};
}
function extractInstanceAndUpdateRecord({ credentialRecord, useMode }) {
	if (credentialRecord.credentialInstances.length === 1 || useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.First) {
		const isFirstUnused = credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUnused;
		const isMultiInstance = credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.MultiInstanceFirstUnused || credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.MultiInstanceFirstUsed;
		const allowsReuse = useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.New ? false : useMode === require_credentialUseTypes.CredentialMultiInstanceUseMode.NewIfReceivedInBatch ? !isMultiInstance : true;
		if (isFirstUnused) credentialRecord.multiInstanceState = credentialRecord.multiInstanceState === require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUnused ? require_credentialUseTypes.CredentialMultiInstanceState.SingleInstanceUsed : require_credentialUseTypes.CredentialMultiInstanceState.MultiInstanceFirstUsed;
		else if (!allowsReuse) throw new require_CredoError.CredoError(`Unable to extract new credential instance from ${credentialRecord.type} with id '${credentialRecord.id}', since it only contains a single credential instance but using a new instance is required due to use mode '${useMode}'.`);
		return {
			isReused: !isFirstUnused,
			credentialInstance: credentialRecord.credentialInstances[0],
			isLastNewInstance: isFirstUnused
		};
	}
	const _credentialInstance = credentialRecord.credentialInstances.pop();
	if (!_credentialInstance) throw new require_CredoError.CredoError(`Unable to extract credential instance from ${credentialRecord.type} with id '${credentialRecord.id}', since the credential record does not contain any credential instances.`);
	return {
		credentialInstance: _credentialInstance,
		isReused: false,
		isLastNewInstance: false
	};
}
function repositoryForRecord(agentContext, record) {
	if (record instanceof require_W3cCredentialRecord.W3cCredentialRecord) return agentContext.resolve(require_W3cCredentialRepository.W3cCredentialRepository);
	if (record instanceof require_W3cV2CredentialRecord.W3cV2CredentialRecord) return agentContext.resolve(require_W3cV2CredentialRepository.W3cV2CredentialRepository);
	if (record instanceof require_MdocRecord.MdocRecord) return agentContext.resolve(require_MdocRepository.MdocRepository);
	return agentContext.resolve(require_SdJwtVcRepository.SdJwtVcRepository);
}
function updateCredentialRecord(agentContext, record) {
	if (record instanceof require_W3cCredentialRecord.W3cCredentialRecord) return agentContext.resolve(require_W3cCredentialRepository.W3cCredentialRepository).update(agentContext, record);
	if (record instanceof require_W3cV2CredentialRecord.W3cV2CredentialRecord) return agentContext.resolve(require_W3cV2CredentialRepository.W3cV2CredentialRepository).update(agentContext, record);
	if (record instanceof require_MdocRecord.MdocRecord) return agentContext.resolve(require_MdocRepository.MdocRepository).update(agentContext, record);
	return agentContext.resolve(require_SdJwtVcRepository.SdJwtVcRepository).update(agentContext, record);
}

//#endregion
exports.canUseInstanceFromCredentialRecord = canUseInstanceFromCredentialRecord;
exports.useInstanceFromCredentialRecord = useInstanceFromCredentialRecord;