// For ESM compatibility
import pkg from 'js-sha3';
const {
  keccak256
} = pkg;
import { BeeArgumentError } from "../utils/error.js";
import { keccak256Hash } from "../utils/hash.js";
const MAX_CHUNK_PAYLOAD_SIZE = 4096;
const SEGMENT_SIZE = 32;
const SEGMENT_PAIR_SIZE = 2 * SEGMENT_SIZE;
const HASH_SIZE = 32;
/**
 * Calculate a Binary Merkle Tree hash for a chunk
 *
 * The BMT chunk address is the hash of the 8 byte span and the root
 * hash of a binary Merkle tree (BMT) built on the 32-byte segments
 * of the underlying data.
 *
 * If the chunk content is less than 4k, the hash is calculated as
 * if the chunk was padded with all zeros up to 4096 bytes.
 *
 * @param chunkContent Chunk data including span and payload as well
 *
 * @returns the keccak256 hash in a byte array
 */

export function bmtHash(chunkContent) {
  const span = chunkContent.slice(0, 8);
  const payload = chunkContent.slice(8);
  const rootHash = bmtRootHash(payload);
  const chunkHashInput = new Uint8Array([...span, ...rootHash]);
  const chunkHash = keccak256Hash(chunkHashInput);
  return chunkHash;
}

function bmtRootHash(payload) {
  if (payload.length > MAX_CHUNK_PAYLOAD_SIZE) {
    throw new BeeArgumentError('invalid data length', payload);
  } // create an input buffer padded with zeros


  let input = new Uint8Array([...payload, ...new Uint8Array(MAX_CHUNK_PAYLOAD_SIZE - payload.length)]);

  while (input.length !== HASH_SIZE) {
    const output = new Uint8Array(input.length / 2); // in each round we hash the segment pairs together

    for (let offset = 0; offset < input.length; offset += SEGMENT_PAIR_SIZE) {
      const hashNumbers = keccak256.array(input.slice(offset, offset + SEGMENT_PAIR_SIZE));
      output.set(hashNumbers, offset / 2);
    }

    input = output;
  }

  return input;
}