import {Buffer} from 'buffer';
import {blake2b as blake2b_js} from 'blakejs';
import md5 from 'md5';
import {ripemd160} from '@ethersproject/sha2';
import sha1 from 'sha1';
import {toUtf8Bytes} from '@ethersproject/strings';

const DefaultHexAlphabetString = '0123456789abcdef';
const SimpleHashAlphabetForHexResult = 'fedcba9876543210';

export function SashaHash(
  data: string,
  reverseArray: boolean = true,
  replaceChar: boolean = true,
): string {
  var tempArr = data.split('');
  if (reverseArray) tempArr.reverse();
  data = tempArr.join('');

  var Blake2BArray = SplitByLength(Blake2BHash(data), 16);
  var Md5Array = SplitByLength(Md5Hash(data), 4);
  var Sha1Array = SplitByLength(Sha1Hash(data), 5);
  var Ripemd160Array = SplitByLength(Ripemd160Hash(data), 5);
  var res = '';

  for (var i = 0; i < 8; i++) {
    if (i < 4) {
      res =
        res + Blake2BArray[i] + Md5Array[i] + Sha1Array[i] + Ripemd160Array[i];
    } else {
      res =
        res + Ripemd160Array[i] + Sha1Array[i] + Md5Array[i] + Blake2BArray[i];
    }
  }

  if (replaceChar)
    return ReplaceChar(
      res,
      DefaultHexAlphabetString,
      SimpleHashAlphabetForHexResult,
    );

  return res;
}

export function Blake2BHash(data: string): string {
  return ByteArrayToHex(blake2b_js(data, undefined, 64));
}

export function Md5Hash(data: string): string {
  return md5(data);
}

export function Ripemd160Hash(data: string): string {
  var str = ripemd160(toUtf8Bytes(data));
  return str.substring(2, str.length);
}

export function Sha1Hash(data: string): string {
  return sha1(data);
}

function ByteArrayToHex(data: Uint8Array): string {
  return Buffer.from(data).toString('hex');
}

function SplitByLength(data: string, maxLength: number): string[] {
  const result: string[] = [];
  for (let index = 0; index < data.length; index += maxLength) {
    result.push(data.substring(index, index + maxLength));
  }
  return result;
}

function ReplaceChar(sourceText: string, fromText: string, toText: string) {
  var input = sourceText.split('');
  var replaced: boolean[] = [];
  for (var j = 0; j < input.length; j++) replaced[j] = false;
  for (var i = 0; i < fromText.length; i++) {
    for (var j = 0; j < input.length; j++) {
      if (replaced[j] === false && input[j] === fromText[i]) {
        input[j] = toText[i];
        replaced[j] = true;
      }
    }
  }
  return input.join('');
}
