"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.acquirePreAuthorizedAccessToken = acquirePreAuthorizedAccessToken;
exports.resolveOpenId4VciOffer = exports.receiveCredentialFromOpenId4VciOffer = exports.customCredentialBindingResolver = void 0;
var _openid4vc = require("@credo-ts/openid4vc");
var _core = require("@credo-ts/core");
var _metadata = require("./metadata");
const resolveOpenId4VciOffer = async ({
  agent,
  data,
  uri,
  authorization
}) => {
  let offerUri = uri;
  if (!offerUri && data) {
    // FIXME: Credo only support credential offer string, but we already parsed it before. So we construct an offer here
    // but in the future we need to support the parsed offer in Credo directly
    offerUri = `openid-credential-offer://credential_offer=${encodeURIComponent(JSON.stringify(data))}`;
  } else if (!offerUri) {
    throw new Error('either data or uri must be provided');
  }
  agent.config.logger.info(`Receiving openid uri ${offerUri}`, {
    offerUri,
    data: data,
    uri: offerUri
  });
  const resolvedCredentialOffer = await agent.modules.openId4VcHolder.resolveCredentialOffer(offerUri);
  if (authorization) {
    throw new Error('Authorization flow is not supported yet as of Credo 0.5.13');
  }
  return resolvedCredentialOffer;
};
exports.resolveOpenId4VciOffer = resolveOpenId4VciOffer;
async function acquirePreAuthorizedAccessToken({
  agent,
  resolvedCredentialOffer,
  txCode
}) {
  return await agent.modules.openId4VcHolder.requestToken({
    resolvedCredentialOffer,
    txCode
  });
}
const customCredentialBindingResolver = async ({
  agent,
  supportedDidMethods,
  keyType,
  supportsAllDidMethods,
  supportsJwk,
  credentialFormat,
  supportedCredentialId,
  resolvedCredentialOffer,
  pidSchemes
}) => {
  // First, we try to pick a did method
  // Prefer did:jwk, otherwise use did:key, otherwise use undefined
  let didMethod = supportsAllDidMethods || supportedDidMethods !== null && supportedDidMethods !== void 0 && supportedDidMethods.includes('did:jwk') ? 'jwk' : supportedDidMethods !== null && supportedDidMethods !== void 0 && supportedDidMethods.includes('did:key') ? 'key' : undefined;

  // If supportedDidMethods is undefined, and supportsJwk is false, we will default to did:key
  // this is important as part of MATTR launchpad support which MUST use did:key but doesn't
  // define which did methods they support
  if (!supportedDidMethods && !supportsJwk) {
    didMethod = 'key';
  }
  const offeredCredentialConfiguration = supportedCredentialId ? resolvedCredentialOffer.offeredCredentialConfigurations[supportedCredentialId] : undefined;
  const shouldKeyBeHardwareBackedForMsoMdoc = (offeredCredentialConfiguration === null || offeredCredentialConfiguration === void 0 ? void 0 : offeredCredentialConfiguration.format) === _openid4vc.OpenId4VciCredentialFormatProfile.MsoMdoc && (pidSchemes === null || pidSchemes === void 0 ? void 0 : pidSchemes.msoMdocDoctypes.includes(offeredCredentialConfiguration.doctype));
  const shouldKeyBeHardwareBackedForSdJwtVc = (offeredCredentialConfiguration === null || offeredCredentialConfiguration === void 0 ? void 0 : offeredCredentialConfiguration.format) === 'vc+sd-jwt' && (pidSchemes === null || pidSchemes === void 0 ? void 0 : pidSchemes.sdJwtVcVcts.includes(offeredCredentialConfiguration.vct));
  const shouldKeyBeHardwareBacked = shouldKeyBeHardwareBackedForSdJwtVc || shouldKeyBeHardwareBackedForMsoMdoc;
  if (!keyType) {
    throw new Error('keyType is required!');
  }
  const key = await agent.wallet.createKey({
    keyType,
    keyBackend: shouldKeyBeHardwareBacked ? _core.KeyBackend.SecureElement : _core.KeyBackend.Software
  });
  if (didMethod) {
    const didResult = await agent.dids.create({
      method: didMethod,
      options: {
        key
      }
    });
    if (didResult.didState.state !== 'finished') {
      throw new Error('DID creation failed.');
    }
    let verificationMethodId;
    if (didMethod === 'jwk') {
      const didJwk = _core.DidJwk.fromDid(didResult.didState.did);
      verificationMethodId = didJwk.verificationMethodId;
    } else {
      const didKey = _core.DidKey.fromDid(didResult.didState.did);
      verificationMethodId = `${didKey.did}#${didKey.key.fingerprint}`;
    }
    return {
      didUrl: verificationMethodId,
      method: 'did'
    };
  }

  // Otherwise we also support plain jwk for sd-jwt only
  if (supportsJwk && (credentialFormat === _openid4vc.OpenId4VciCredentialFormatProfile.SdJwtVc || credentialFormat === _openid4vc.OpenId4VciCredentialFormatProfile.MsoMdoc)) {
    return {
      method: 'jwk',
      jwk: (0, _core.getJwkFromKey)(key)
    };
  }
  throw new Error(`No supported binding method could be found. Supported methods are did:key and did:jwk, or plain jwk for sd-jwt/mdoc. Issuer supports ${supportsJwk ? 'jwk, ' : ''}${(supportedDidMethods === null || supportedDidMethods === void 0 ? void 0 : supportedDidMethods.join(', ')) ?? 'Unknown'}`);
};
exports.customCredentialBindingResolver = customCredentialBindingResolver;
const receiveCredentialFromOpenId4VciOffer = async ({
  agent,
  resolvedCredentialOffer,
  tokenResponse,
  credentialConfigurationIdsToRequest,
  clientId,
  pidSchemes
}) => {
  const offeredCredentialsToRequest = credentialConfigurationIdsToRequest ? resolvedCredentialOffer.offeredCredentials.filter(offered => credentialConfigurationIdsToRequest.includes(offered.id)) : [resolvedCredentialOffer.offeredCredentials[0]];
  if (offeredCredentialsToRequest.length === 0) {
    throw new Error(`Parameter 'credentialConfigurationIdsToRequest' with values ${credentialConfigurationIdsToRequest} is not a credential_configuration_id in the credential offer.`);
  }
  const credentials = await agent.modules.openId4VcHolder.requestCredentials({
    resolvedCredentialOffer,
    ...tokenResponse,
    clientId,
    credentialsToRequest: credentialConfigurationIdsToRequest,
    verifyCredentialStatus: false,
    allowedProofOfPossessionSignatureAlgorithms: [
    // NOTE: MATTR launchpad for JFF MUST use EdDSA. So it is important that the default (first allowed one)
    // is EdDSA. The list is ordered by preference, so if no suites are defined by the issuer, the first one
    // will be used
    _core.JwaSignatureAlgorithm.EdDSA, _core.JwaSignatureAlgorithm.ES256],
    credentialBindingResolver: async ({
      supportedDidMethods,
      keyType,
      supportsAllDidMethods,
      supportsJwk,
      credentialFormat,
      supportedCredentialId
    }) => {
      return customCredentialBindingResolver({
        agent,
        supportedDidMethods,
        keyType,
        supportsAllDidMethods,
        supportsJwk,
        credentialFormat,
        supportedCredentialId,
        resolvedCredentialOffer,
        pidSchemes
      });
    }
  });

  // We only support one credential for now
  const [firstCredential] = credentials;
  if (!firstCredential) throw new Error('Error retrieving credential using pre authorized flow: firstCredential undefined!.');
  let record;
  if (typeof firstCredential === 'string') {
    throw new Error('Error retrieving credential using pre authorized flow: firstCredential is string.');
  }
  if ('compact' in firstCredential.credential) {
    // TODO: add claimFormat to SdJwtVc
    record = new _core.SdJwtVcRecord({
      compactSdJwtVc: firstCredential.credential.compact
    });
  } else if (firstCredential.credential instanceof _core.Mdoc) {
    record = new _core.MdocRecord({
      mdoc: firstCredential.credential
    });
  } else {
    record = new _core.W3cCredentialRecord({
      credential: firstCredential.credential,
      // We don't support expanded types right now, but would become problem when we support JSON-LD
      tags: {}
    });
  }
  const notificationMetadata = {
    ...firstCredential.notificationMetadata
  };
  if (notificationMetadata) {
    _metadata.temporaryMetaVanillaObject.notificationMetadata = notificationMetadata;
  }
  const openId4VcMetadata = (0, _metadata.extractOpenId4VcCredentialMetadata)(resolvedCredentialOffer.offeredCredentials[0], {
    id: resolvedCredentialOffer.metadata.issuer,
    display: resolvedCredentialOffer.metadata.credentialIssuerMetadata.display
  });
  (0, _metadata.setOpenId4VcCredentialMetadata)(record, openId4VcMetadata);
  return record;
};
exports.receiveCredentialFromOpenId4VciOffer = receiveCredentialFromOpenId4VciOffer;
//# sourceMappingURL=offerResolve.js.map