'use strict';

var cryptoWasmTs = require('@docknetwork/crypto-wasm-ts');
var b58 = require('bs58');
var utils_types_bytes = require('../utils/types/bytes.cjs');
var utils_types_array = require('../utils/types/array.cjs');
require('multiformats/bases/base58');
require('varint');
require('../utils/encoding/ss-58.cjs');
var vc_crypto_Bls12381BBSSignatureDock2022 = require('./crypto/Bls12381BBSSignatureDock2022.cjs');
var vc_crypto_common_DockCryptoSignatureProof = require('./crypto/common/DockCryptoSignatureProof.cjs');
var vc_crypto_constants = require('./crypto/constants.cjs');
var vc_documentLoader = require('./document-loader.cjs');
require('./crypto/Bls12381BBDT16KeyPairDock2024.cjs');
var vc_crypto_Bls12381BBDT16MACDock2024 = require('./crypto/Bls12381BBDT16MACDock2024.cjs');
require('./crypto/Bls12381BBDT16MACProofDock2024.cjs');
require('./crypto/Bls12381BBSKeyPairDock2023.cjs');
var vc_crypto_Bls12381BBSSignatureDock2023 = require('./crypto/Bls12381BBSSignatureDock2023.cjs');
require('./crypto/Bls12381BBSSignatureProofDock2022.cjs');
require('./crypto/Bls12381BBSSignatureProofDock2023.cjs');
require('./crypto/Bls12381BDDT16KeyPairDock2024.cjs');
require('./crypto/Bls12381BDDT16MACDock2024.cjs');
require('./crypto/Bls12381BDDT16MACProofDock2024.cjs');
require('./crypto/Bls12381G2KeyPairDock2022.cjs');
require('./crypto/Bls12381PSKeyPairDock2023.cjs');
var vc_crypto_Bls12381PSSignatureDock2023 = require('./crypto/Bls12381PSSignatureDock2023.cjs');
require('./crypto/Bls12381PSSignatureProofDock2023.cjs');
require('@juanelas/base64');
require('../keypairs/keypair-secp256k1.cjs');
require('./crypto/common/CustomLinkedDataSignature.cjs');
require('@stablelib/ed25519');
require('../types/public-keys/public-key.cjs');
require('../types/public-keys/public-key-sr25519-value.cjs');
require('../types/public-keys/public-key-ed25519-value.cjs');
require('../types/public-keys/public-key-secp256k1-value.cjs');
require('../types/public-keys/public-key-x25519-value.cjs');
require('../types/signatures/signature-value.cjs');
require('../types/signatures/signature.cjs');
require('../keypairs/dock-keypair.cjs');
require('@transmute/json-web-signature');
var vc_crypto_common_DockCryptoSignature = require('./crypto/common/DockCryptoSignature.cjs');
require('crypto');
require('../utils/interfaces.cjs');
require('../utils/assert.cjs');
require('../utils/error.cjs');
require('../utils/types/string.cjs');
require('../utils/types/iterable.cjs');
require('../utils/types/object.cjs');
require('../utils/inheritance.cjs');
require('../utils/types/set.cjs');
require('blake2b');
require('./crypto/common/DockCryptoKeyPair.cjs');
require('jsonld-signatures');
require('json-stringify-deterministic');
require('semver/preload.js');
require('base64url');
require('jsonld');
require('../types/did/document/verification-method-ref.cjs');
require('../types/generic/typed-enum.cjs');
require('../types/generic/with-base.cjs');
require('../types/generic/with-catch-null.cjs');
require('../types/generic/with-eq.cjs');
require('../types/generic/any-of.cjs');
require('../types/generic/with-from.cjs');
require('../types/generic/with-from-json-bytes.cjs');
require('../types/generic/typed-null.cjs');
require('../types/generic/create-placeholder.cjs');
require('../types/generic/typed-bytes.cjs');
require('../types/generic/typed-string.cjs');
require('../types/generic/typed-array.cjs');
require('../types/generic/typed-tuple.cjs');
require('../types/generic/typed-number.cjs');
require('../types/generic/typed-set.cjs');
require('../types/generic/typed-map.cjs');
require('../types/generic/typed-struct.cjs');
require('uuid');
require('js-sha256');
require('../types/generic/with-qualifier.cjs');
require('../types/generic/utils.cjs');
require('../types/generic/typed-bytes-array.cjs');
require('../types/did/onchain/typed-did/index.cjs');
require('../types/did/onchain/typed-did/did-method-key/did-method-key-public-key.cjs');
require('../utils/encoding/base-58-btc.cjs');
require('../types/generic/sized.cjs');
require('../utils/types/number.cjs');
require('../types/did/onchain/constants.cjs');
require('../types/did/onchain/typed-did/signature.cjs');
require('../types/did/onchain/typed-did/did-method-key/did-method-key-signature.cjs');
require('../types/signatures/signature-ed25519-value.cjs');
require('../types/signatures/signature-secp256k1-value.cjs');
require('../types/signatures/signature-sr25519-value.cjs');
require('../types/did/onchain/typed-did/dock-did-value.cjs');
require('../types/generic/typed-uuid.cjs');
require('../types/did/onchain/typed-did/cheqd-did.cjs');
require('./jws.cjs');
require('./contexts.cjs');
require('./contexts/vc-examples-v1.cjs');
require('./contexts/security_context.cjs');
require('./contexts/status-list-21.cjs');
require('./contexts/private-status-list-21.cjs');
require('../utils/json-fetch.cjs');
require('@docknetwork/crypto-wasm-ts/lib/index.js');
require('elliptic');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var b58__default = /*#__PURE__*/_interopDefault(b58);

const SIG_NAME_TO_PROOF_NAME = Object.setPrototypeOf(
  {
    [vc_crypto_constants.Bls12381BBSSigDockSigName]: vc_crypto_constants.Bls12381BBSSigProofDockSigName,
    [vc_crypto_constants.Bls12381BBS23SigDockSigName]: vc_crypto_constants.Bls12381BBS23SigProofDockSigName,
    [vc_crypto_constants.Bls12381PSSigDockSigName]: vc_crypto_constants.Bls12381PSSigProofDockSigName,
    [vc_crypto_constants.Bls12381BBDT16MacDockName]: vc_crypto_constants.Bls12381BBDT16MacProofDockName,
  },
  null,
);

class Presentation {
  /**
   * Create a new BbsPlusPresentation instance.
   * @constructor
   */
  constructor() {
    this.presBuilder = new cryptoWasmTs.PresentationBuilder();
  }

  /**
   * Species attributes to be revealed in the credential
   * @param {number} credentialIndex
   * @param {Array.<string>} attributes
   */
  addAttributeToReveal(credentialIndex, attributes = []) {
    utils_types_array.ensureArray(attributes);
    this.presBuilder.markAttributesRevealed(
      credentialIndex,
      new Set(attributes),
    );
  }

  /**
   * Create a presentation
   * @param options
   * @returns {object}
   */
  createPresentation(options = {}) {
    const { nonce, context } = options;
    if (nonce) {
      this.presBuilder.nonce = utils_types_bytes.normalizeOrConvertStringToU8a(nonce);
    }
    if (context) {
      this.presBuilder.context = context;
    }
    const pres = this.presBuilder.finalize();
    return pres.toJSON();
  }

  /**
   * Adds a JSON-LD credential to be presented
   * @param credentialLD
   * @param options
   * @returns {Promise<number>}
   */
  async addCredentialToPresent(credentialLD, options = {}) {
    if (options.documentLoader && options.resolver) {
      throw new Error(
        'Passing resolver and documentLoader results in resolver being ignored, please re-factor.',
      );
    }
    if (!cryptoWasmTs.isWasmInitialized()) {
      await cryptoWasmTs.initializeWasm();
    }

    const documentLoader = options.documentLoader || vc_documentLoader(options.resolver);

    const json = typeof credentialLD === 'string'
      ? JSON.parse(credentialLD)
      : credentialLD;

    const { proof } = json;

    if (!proof) {
      throw new Error('Credential does not have a proof');
    }

    let Signature;
    let PublicKey;
    let isKvac = false;
    let pk;

    switch (proof.type) {
      case vc_crypto_constants.Bls12381BBSSigDockSigName:
        Signature = vc_crypto_Bls12381BBSSignatureDock2022;
        PublicKey = cryptoWasmTs.BBSPlusPublicKeyG2;
        break;
      case vc_crypto_constants.Bls12381BBS23SigDockSigName:
        Signature = vc_crypto_Bls12381BBSSignatureDock2023;
        PublicKey = cryptoWasmTs.BBSPublicKey;
        break;
      case vc_crypto_constants.Bls12381PSSigDockSigName:
        Signature = vc_crypto_Bls12381PSSignatureDock2023;
        PublicKey = cryptoWasmTs.PSPublicKey;
        break;
      case vc_crypto_constants.Bls12381BBDT16MacDockName:
        Signature = vc_crypto_Bls12381BBDT16MACDock2024;
        PublicKey = undefined;
        isKvac = true;
        break;
      default:
        throw new Error(`Invalid proof type ${proof.type}`);
    }

    if (!isKvac) {
      const keyDocument = await Signature.getVerificationMethod({
        proof,
        documentLoader,
      });

      const pkRaw = b58__default.default.decode(keyDocument.publicKeyBase58);
      pk = new PublicKey(pkRaw);
    }

    const convertedCredential = Signature.convertCredentialForPresBuilding({
      document: json,
    });
    const idx = this.presBuilder.addCredential(convertedCredential, pk);

    // Enforce revealing of verificationMethod and type
    // We also require context and type for JSON-LD
    const toReveal = [
      'proof.type',
      'proof.verificationMethod',
      '@context',
      'type',
    ];
    // If the issuer field is defined in the credential, reveal it.
    if (json.issuer !== undefined) {
      if (typeof json.issuer === 'string') {
        toReveal.push('issuer');
      } else if (Array.isArray(json.issuer)) {
        throw new Error(`"issuer" cant be an array but was ${json.issuer}`);
      } else if (typeof json.issuer === 'object') {
        const [names, _] = cryptoWasmTs.flattenObjectToKeyValuesList(json.issuer);
        toReveal.push(...names.map((n) => `issuer.${n}`));
      } else {
        throw new Error(`Unexpected value for "issuer" ${json.issuer}`);
      }
    }
    this.addAttributeToReveal(idx, toReveal);
    return idx;
  }

  deriveCredentials(options) {
    const presentation = this.createPresentation(options);
    const { credentials } = presentation.spec;
    if (credentials.length > 1) {
      throw new Error(
        'Cannot derive from multiple credentials in a presentation',
      );
    }

    return credentials.map((credential) => {
      if (!credential.revealedAttributes.proof) {
        throw new Error('Credential proof is not revealed, it should be');
      }

      const date = new Date().toISOString();
      const type = SIG_NAME_TO_PROOF_NAME[credential.revealedAttributes.proof.type];
      if (type == null) {
        throw new Error(
          `Failed to map credential signature type to the proof type: ${credential.revealedAttributes.proof.type}`,
        );
      }

      const w3cFormattedCredential = {
        ...credential.revealedAttributes,
        // ID required for W£C formatted credentials, if not revealed used a static URI
        id: credential.revealedAttributes.id || vc_crypto_common_DockCryptoSignatureProof.DOCK_ANON_CREDENTIAL_ID,
        '@context': JSON.parse(credential.revealedAttributes['@context']),
        type: JSON.parse(credential.revealedAttributes.type),
        credentialSchema: vc_crypto_common_DockCryptoSignature.isCredVerGte060(credential.version)
          ? credential.schema
          : JSON.parse(credential.schema),
        issuer:
          credential.revealedAttributes.issuer
          || credential.revealedAttributes.proof.verificationMethod.split('#')[0],
        issuanceDate: credential.revealedAttributes.issuanceDate || date,
        proof: {
          proofPurpose: 'assertionMethod',
          created: date,
          ...credential.revealedAttributes.proof,
          type,
          // Question: Why each cred will have the same proof, nonce, context, etc. They don't apply here. And is the same proof repeatedly verified?
          proofValue: presentation.proof,
          nonce: presentation.nonce,
          context: presentation.context,
          attributeCiphertexts: presentation.attributeCiphertexts,
          attributeEqualities: presentation.spec.attributeEqualities,
          boundedPseudonyms: presentation.spec.boundedPseudonyms,
          unboundedPseudonyms: presentation.spec.unboundedPseudonyms,
          version: credential.version,
          // This is the presentation version and not the credential version. Continuing the stupidity by adding presentation version to the credential version so that it can be later retrieved
          presVersion: presentation.version,
          sigType: credential.sigType,
          bounds: credential.bounds,
        },
      };

      if (credential.status) {
        w3cFormattedCredential.credentialStatus = credential.status;
      }

      return w3cFormattedCredential;
    });
  }
}

module.exports = Presentation;
//# sourceMappingURL=presentation.cjs.map
