'use strict';

var vc_presentations = require('./presentations.cjs');
var utils_types_array = require('../utils/types/array.cjs');
var utils_types_object = require('../utils/types/object.cjs');
var utils_types_string = require('../utils/types/string.cjs');
require('crypto');
require('bs58');
require('multiformats/bases/base58');
require('varint');
require('../utils/encoding/ss-58.cjs');
var utils_ident_ensureIdent = require('../utils/ident/ensure-ident.cjs');
var vc_verifiableCredential = require('./verifiable-credential.cjs');
require('jsonld');
require('jsonld-signatures');
require('@docknetwork/crypto-wasm-ts');
require('@docknetwork/vc-delegation-engine');
require('./credentials.cjs');
require('@digitalcredentials/vc-status-list');
require('base64url');
require('./CredentialIssuancePurpose.cjs');
require('./helpers.cjs');
require('@transmute/json-web-signature');
require('./document-loader.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('./crypto/Bls12381BBDT16KeyPairDock2024.cjs');
require('./crypto/constants.cjs');
require('./crypto/common/DockCryptoKeyPair.cjs');
require('../utils/types/bytes.cjs');
require('../utils/interfaces.cjs');
require('../utils/assert.cjs');
require('../utils/error.cjs');
require('../utils/types/iterable.cjs');
require('../utils/inheritance.cjs');
require('../utils/types/set.cjs');
require('./crypto/Bls12381BBDT16MACDock2024.cjs');
require('@docknetwork/crypto-wasm-ts/lib/index.js');
require('./crypto/common/DockCryptoSignature.cjs');
require('json-stringify-deterministic');
require('semver/preload.js');
require('./crypto/common/CustomLinkedDataSignature.cjs');
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('blake2b');
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/public-keys/public-key.cjs');
require('../types/public-keys/public-key-x25519-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-sr25519-value.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-value.cjs');
require('../types/signatures/signature-ed25519-value.cjs');
require('../types/signatures/signature-secp256k1-value.cjs');
require('../types/signatures/signature.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('./crypto/Bls12381BBDT16MACProofDock2024.cjs');
require('./crypto/common/DockCryptoSignatureProof.cjs');
require('./crypto/Bls12381BBSKeyPairDock2023.cjs');
require('./crypto/Bls12381BBSSignatureDock2022.cjs');
require('./crypto/Bls12381G2KeyPairDock2022.cjs');
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/Bls12381PSKeyPairDock2023.cjs');
require('./crypto/Bls12381PSSignatureDock2023.cjs');
require('./crypto/Bls12381PSSignatureProofDock2023.cjs');
require('./crypto/EcdsaSecp256k1Signature2019.cjs');
require('./crypto/EcdsaSecp256k1VerificationKey2019.cjs');
require('@juanelas/base64');
require('../keypairs/keypair-secp256k1.cjs');
require('elliptic');
require('../keypairs/dock-keypair.cjs');
require('../utils/encoding/multibase.cjs');
require('./crypto/Ed25519Signature2018.cjs');
require('./crypto/Ed25519VerificationKey2018.cjs');
require('../keypairs/keypair-ed25519.cjs');
require('@stablelib/ed25519');
require('./crypto/Ed25519Signature2020.cjs');
require('./crypto/Ed25519VerificationKey2020.cjs');
require('./crypto/JsonWebSignature2020.cjs');
require('../keypairs/did-keypair.cjs');
require('../types/did/onchain/did-key.cjs');
require('../types/offchain-signatures/params/index.cjs');
require('../types/offchain-signatures/params/value.cjs');
require('../types/generic/option.cjs');
require('../types/offchain-signatures/curve-type.cjs');
require('../types/offchain-signatures/params/id.cjs');
require('../types/generic/with-from-dock-id.cjs');
require('../types/offchain-signatures/public-keys/index.cjs');
require('../types/generic/with-prop.cjs');
require('../types/generic/with-props.cjs');
require('../types/offchain-signatures/public-keys/value.cjs');
require('../types/offchain-signatures/public-keys/ref.cjs');
require('../types/offchain-signatures/public-keys/id.cjs');
require('../types/did/onchain/verification-relationship.cjs');
require('../types/did/document/verification-method-ref-or-ident-ref.cjs');
require('../types/did/document/ident-ref.cjs');
require('./schema.cjs');
require('jsonschema');
require('./constants.cjs');
require('./revocation.cjs');
require('blakejs');
require('../utils/ident/matchers.cjs');

// import DIDResolver from "../resolver/did/did-resolver"; // eslint-disable-line

const DEFAULT_CONTEXT = 'https://www.w3.org/2018/credentials/v1';
const DEFAULT_TYPE = 'VerifiablePresentation';

/**
 * @typedef {object} VerifiablePresentationVerificationResult The presentation verification result
 * @property {object} presentationResult Is this presentqtion verified or not
 * @property {array} credentialResults Verification results
 * @property {Boolean} verified Is verified or not
 * @property {any} [error] Optional error
 */

/**
 * Representation of a Verifiable Presentation.
 */
class VerifiablePresentation {
  /**
   * Create a new Verifiable Presentation instance.
   * @param {string} id - id of the presentation
   * @constructor
   */
  constructor(id) {
    utils_ident_ensureIdent.ensureURI(id);
    this.id = id;
    this.context = [DEFAULT_CONTEXT];
    this.type = [DEFAULT_TYPE];
    this.credentials = [];
    this.proof = null;
  }

  static fromJSON(json) {
    const {
      verifiableCredential, id, type, ...rest
    } = json;
    const vp = new VerifiablePresentation(id);

    if (type) {
      vp.type = [];
      if (type.length !== undefined) {
        type.forEach((typeVal) => {
          vp.addType(typeVal);
        });
      } else {
        vp.addType(type);
      }
    } else {
      throw new Error(
        'No type found in JSON object, verifiable presentations must have a type field.',
      );
    }

    const context = rest['@context'];
    if (context) {
      vp.setContext(rest['@context']);
      delete rest['@context'];
    } else {
      throw new Error(
        'No context found in JSON object, verifiable presentations must have a @context field.',
      );
    }

    if (verifiableCredential) {
      if (verifiableCredential.length) {
        verifiableCredential.forEach((credential) => {
          vp.addCredential(credential);
        });
      } else {
        vp.addCredential(verifiableCredential);
      }
    }

    Object.assign(vp, rest);
    return vp;
  }

  /**
   * Sets the context to the given value, overrding all others
   * @param {string|object} context - Context to assign
   * @returns {VerifiablePresentation}
   */
  setContext(context) {
    if (!utils_types_object.isObject(context) && !Array.isArray(context)) {
      utils_ident_ensureIdent.ensureURI(context);
    }
    this.context = context;
    return this;
  }

  /**
   * Add a context to this Presentation's context array. Duplicates are omitted.
   * @param {string|object} context - Context to add to the presentation context array
   * @returns {VerifiablePresentation}
   */
  addContext(context) {
    if (!utils_types_object.isObject(context)) {
      utils_ident_ensureIdent.ensureURI(context);
    }
    this.context = utils_types_array.getUniqueElementsFromArray(
      [...this.context, context],
      JSON.stringify,
    );
    return this;
  }

  /**
   * Add a type to this Presentation's type array. Duplicates are omitted.
   * @param {string} type - Type to add to the presentation type array
   * @returns {VerifiablePresentation}
   */
  addType(type) {
    utils_types_string.ensureString(type);
    this.type = [...new Set([...this.type, type])];
    return this;
  }

  /**
   * Set a holder for this Presentation
   * @param {string} holder - Holder to add to the presentation
   * @returns {VerifiablePresentation}
   */
  setHolder(holder) {
    utils_ident_ensureIdent.ensureURI(holder);
    this.holder = holder;
    return this;
  }

  /**
   * Add a Verifiable Credential to this Presentation.
   * @param {object} credential -  Verifiable Credential for the presentation
   * @returns {VerifiablePresentation}
   */
  addCredential(credential) {
    let cred = credential;
    if (credential instanceof vc_verifiableCredential) {
      cred = credential.toJSON();
    }
    utils_types_object.ensureObjectWithId(cred, 'credential');
    this.credentials.push(cred);

    return this;
  }

  /**
   * Add multiple Verifiable Credentials to this Presentation.
   * @param {Array<object>} credentials -  Verifiable Credential for the presentation
   * @returns {VerifiablePresentation}
   */
  addCredentials(credentials) {
    credentials.forEach(this.addCredential.bind(this));
  }

  /**
   * Define the JSON representation of a Verifiable Presentation.
   * @returns {object}
   */
  toJSON() {
    const { context, credentials, ...rest } = this;
    return {
      '@context': context,
      verifiableCredential: credentials,
      ...rest,
    };
  }

  /**
   * Sign a Verifiable Presentation using the provided keyDoc
   * @param {object} keyDoc - document with `id`, `controller`, `type`, `privateKeyBase58` and `publicKeyBase58`
   * @param {string} challenge - proof challenge Required.
   * @param {string} domain - proof domain (optional)
   * @param {DIDResolver} [resolver] - Resolver for DIDs.
   * @param {Boolean} [compactProof] - Whether to compact the JSON-LD or not.
   * @returns {Promise<VerifiablePresentation>}
   */
  async sign(keyDoc, challenge, domain, resolver = null, compactProof = true) {
    const signedVP = await vc_presentations.signPresentation(
      this.toJSON(),
      keyDoc,
      challenge,
      domain,
      resolver,
      compactProof,
    );
    this.context = signedVP['@context'];
    this.proof = signedVP.proof;
    return this;
  }

  /**
   * Verify a Verifiable Presentation
   * @param {object} [params] Verify parameters (TODO: add type info for this object)
   * @returns {Promise<VerifiablePresentationVerificationResult>} - verification result.
   */
  async verify({
    challenge,
    domain,
    resolver = null,
    compactProof = true,
    skipRevocationCheck = false,
    skipSchemaCheck = false,
    verifyMatchingIssuersForRevocation = true,
    suite = [],
  } = {}) {
    if (!this.proof) {
      throw new Error('The current VerifiablePresentation has no proof.');
    }

    return vc_presentations.verifyPresentation(this.toJSON(), {
      challenge,
      domain,
      resolver,
      compactProof,
      skipRevocationCheck,
      skipSchemaCheck,
      verifyMatchingIssuersForRevocation,
      suite,
    });
  }
}

module.exports = VerifiablePresentation;
//# sourceMappingURL=verifiable-presentation.cjs.map
