import { PresentationBuilder, isWasmInitialized, initializeWasm, flattenObjectToKeyValuesList, PSPublicKey, BBSPublicKey, BBSPlusPublicKeyG2 } from '@docknetwork/crypto-wasm-ts';
import b58 from 'bs58';
import { normalizeOrConvertStringToU8a } from '../utils/types/bytes.js';
import { ensureArray } from '../utils/types/array.js';
import 'multiformats/bases/base58';
import 'varint';
import '../utils/encoding/ss-58.js';
import Bls12381BBSSignatureDock2022 from './crypto/Bls12381BBSSignatureDock2022.js';
import { DOCK_ANON_CREDENTIAL_ID } from './crypto/common/DockCryptoSignatureProof.js';
import { Bls12381BBDT16MacProofDockName, Bls12381PSSigProofDockSigName, Bls12381BBS23SigProofDockSigName, Bls12381BBSSigProofDockSigName, Bls12381BBDT16MacDockName, Bls12381PSSigDockSigName, Bls12381BBS23SigDockSigName, Bls12381BBSSigDockSigName } from './crypto/constants.js';
import documentLoader from './document-loader.js';
import './crypto/Bls12381BBDT16KeyPairDock2024.js';
import Bls12381BBDT16MACDock2024 from './crypto/Bls12381BBDT16MACDock2024.js';
import './crypto/Bls12381BBDT16MACProofDock2024.js';
import './crypto/Bls12381BBSKeyPairDock2023.js';
import Bls12381BBSSignatureDock2023 from './crypto/Bls12381BBSSignatureDock2023.js';
import './crypto/Bls12381BBSSignatureProofDock2022.js';
import './crypto/Bls12381BBSSignatureProofDock2023.js';
import './crypto/Bls12381BDDT16KeyPairDock2024.js';
import './crypto/Bls12381BDDT16MACDock2024.js';
import './crypto/Bls12381BDDT16MACProofDock2024.js';
import './crypto/Bls12381G2KeyPairDock2022.js';
import './crypto/Bls12381PSKeyPairDock2023.js';
import Bls12381PSSignatureDock2023 from './crypto/Bls12381PSSignatureDock2023.js';
import './crypto/Bls12381PSSignatureProofDock2023.js';
import '@juanelas/base64';
import '../keypairs/keypair-secp256k1.js';
import './crypto/common/CustomLinkedDataSignature.js';
import '@stablelib/ed25519';
import '../types/public-keys/public-key.js';
import '../types/public-keys/public-key-sr25519-value.js';
import '../types/public-keys/public-key-ed25519-value.js';
import '../types/public-keys/public-key-secp256k1-value.js';
import '../types/public-keys/public-key-x25519-value.js';
import '../types/signatures/signature-value.js';
import '../types/signatures/signature.js';
import '../keypairs/dock-keypair.js';
import '@transmute/json-web-signature';
import { isCredVerGte060 } from './crypto/common/DockCryptoSignature.js';
import 'crypto';
import '../utils/interfaces.js';
import '../utils/assert.js';
import '../utils/error.js';
import '../utils/types/string.js';
import '../utils/types/iterable.js';
import '../utils/types/object.js';
import '../utils/inheritance.js';
import '../utils/types/set.js';
import 'blake2b';
import './crypto/common/DockCryptoKeyPair.js';
import 'jsonld-signatures';
import 'json-stringify-deterministic';
import 'semver/preload.js';
import 'base64url';
import 'jsonld';
import '../types/did/document/verification-method-ref.js';
import '../types/generic/typed-enum.js';
import '../types/generic/with-base.js';
import '../types/generic/with-catch-null.js';
import '../types/generic/with-eq.js';
import '../types/generic/any-of.js';
import '../types/generic/with-from.js';
import '../types/generic/with-from-json-bytes.js';
import '../types/generic/typed-null.js';
import '../types/generic/create-placeholder.js';
import '../types/generic/typed-bytes.js';
import '../types/generic/typed-string.js';
import '../types/generic/typed-array.js';
import '../types/generic/typed-tuple.js';
import '../types/generic/typed-number.js';
import '../types/generic/typed-set.js';
import '../types/generic/typed-map.js';
import '../types/generic/typed-struct.js';
import 'uuid';
import 'js-sha256';
import '../types/generic/with-qualifier.js';
import '../types/generic/utils.js';
import '../types/generic/typed-bytes-array.js';
import '../types/did/onchain/typed-did/index.js';
import '../types/did/onchain/typed-did/did-method-key/did-method-key-public-key.js';
import '../utils/encoding/base-58-btc.js';
import '../types/generic/sized.js';
import '../utils/types/number.js';
import '../types/did/onchain/constants.js';
import '../types/did/onchain/typed-did/signature.js';
import '../types/did/onchain/typed-did/did-method-key/did-method-key-signature.js';
import '../types/signatures/signature-ed25519-value.js';
import '../types/signatures/signature-secp256k1-value.js';
import '../types/signatures/signature-sr25519-value.js';
import '../types/did/onchain/typed-did/dock-did-value.js';
import '../types/generic/typed-uuid.js';
import '../types/did/onchain/typed-did/cheqd-did.js';
import './jws.js';
import './contexts.js';
import './contexts/vc-examples-v1.js';
import './contexts/security_context.js';
import './contexts/status-list-21.js';
import './contexts/private-status-list-21.js';
import '../utils/json-fetch.js';
import '@docknetwork/crypto-wasm-ts/lib/index.js';
import 'elliptic';

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

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

  /**
   * Species attributes to be revealed in the credential
   * @param {number} credentialIndex
   * @param {Array.<string>} attributes
   */
  addAttributeToReveal(credentialIndex, attributes = []) {
    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 = 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 (!isWasmInitialized()) {
      await initializeWasm();
    }

    const documentLoader$1 = options.documentLoader || 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 Bls12381BBSSigDockSigName:
        Signature = Bls12381BBSSignatureDock2022;
        PublicKey = BBSPlusPublicKeyG2;
        break;
      case Bls12381BBS23SigDockSigName:
        Signature = Bls12381BBSSignatureDock2023;
        PublicKey = BBSPublicKey;
        break;
      case Bls12381PSSigDockSigName:
        Signature = Bls12381PSSignatureDock2023;
        PublicKey = PSPublicKey;
        break;
      case Bls12381BBDT16MacDockName:
        Signature = Bls12381BBDT16MACDock2024;
        PublicKey = undefined;
        isKvac = true;
        break;
      default:
        throw new Error(`Invalid proof type ${proof.type}`);
    }

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

      const pkRaw = b58.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, _] = 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 || DOCK_ANON_CREDENTIAL_ID,
        '@context': JSON.parse(credential.revealedAttributes['@context']),
        type: JSON.parse(credential.revealedAttributes.type),
        credentialSchema: 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;
    });
  }
}

export { Presentation as default };
//# sourceMappingURL=presentation.js.map
