'use strict';

var mrklt = require('mrklt');
require('../common/abstract-api-provider.cjs');
var modules_abstract_common_abstractBaseModule = require('../common/abstract-base-module.cjs');
require('../../../utils/types/array.cjs');
require('crypto');
var utils_inheritance = require('../../../utils/inheritance.cjs');
require('bs58');
require('multiformats/bases/base58');
require('varint');
require('../../../utils/encoding/ss-58.cjs');
var types_anchor_index = require('../../../types/anchor/index.cjs');
require('../../../utils/types/object.cjs');
require('../../../utils/types/iterable.cjs');
require('../../../utils/types/set.cjs');
require('blake2b');
require('../../../utils/types/bytes.cjs');
require('../../../utils/interfaces.cjs');
require('../../../utils/assert.cjs');
require('../../../utils/error.cjs');
require('../../../utils/types/string.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/sized.cjs');
require('../../../utils/types/number.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');

/* eslint-disable camelcase */

/** Class to create and query anchors from chain. */
let AbstractAnchorModule$1 = class AbstractAnchorModule extends modules_abstract_common_abstractBaseModule {
  /**
   * Write anchor on chain
   * @param anchor
   * @returns {Promise<*>}
   */
  async deploy(anchor, params) {
    return await this.signAndSend(await this.deployTx(anchor), params);
  }

  /**
   * Query anchor from chain
   * @param {AnchorHash} anchor
   * @param {boolean} preHashed - If the anchor has already been hashed.
   * @returns {Promise<Anchor>} - The promise will either successfully resolve to the block number where anchor was created
   * or reject with an error.
   */
  async get(_anchorKey, _preHashed = false) {
    throw new Error('Unimplemented');
  }

  /**
   * Batch multiple documents in binary merkle tree and return the root and proofs for each document
   * @param documents
   * @returns {Array} - An 2 element array where 1st element is root and 2nd is an array with proofs for
   * each document.
   */
  static batchDocumentsInMerkleTree(documents) {
    // Hash all documents
    const leafHashes = documents.map((doc) => types_anchor_index.Anchor.hash(doc).bytes);

    // If only one document was hashed, just return that as the root with no proofs (single anchor)
    if (leafHashes.length === 1) {
      return [leafHashes[0], []];
    }

    // Concatenate all leaf hashes into one bytearray
    const packed = new Uint8Array(leafHashes.map((a) => [...a]).flat());
    const [root, proofs] = mrklt.construct(packed);
    return [Uint8Array.from(root), proofs, leafHashes];
  }

  /**
   * Verify inclusion proof of document in a merkle tree with given root. The document is hashed to form a leaf first
   * @param document
   * @param proof
   * @param root
   * @returns {boolean}
   */
  static verifyMerkleProofOfDocument(document, proof, root) {
    const hash = types_anchor_index.Anchor.hash(document).bytes;
    return this.verifyMerkleProofOfLeaf(hash, proof, root);
  }

  /**
   * Verify inclusion proof of leaf in a merkle tree with given root.
   * @param leaf
   * @param proof
   * @param root
   * @returns {boolean}
   */
  static verifyMerkleProofOfLeaf(leaf, proof, root) {
    /* eslint-disable camelcase */
    const calculatedRoot = mrklt.verify_proof(leaf, proof);
    return (
      calculatedRoot.length === root.length
      && calculatedRoot.every((v, i) => v === root[i])
    );
  }
};

var AbstractAnchorModule = utils_inheritance.withExtendedPrototypeProperties(
  ['deployTx', 'get'],
  AbstractAnchorModule$1,
);

module.exports = AbstractAnchorModule;
//# sourceMappingURL=module.cjs.map
