import { toBase64 } from "@cosmjs/encoding";
import { MULTIBASE_BASE58BTC_HEADER } from "./constants";
import base58 from "bs58";
export const b64toUint8Array = function (b64) {
  return Uint8Array.from(Buffer.from(b64, "base64"));
};
export const b64toJson = function (b64) {
  return JSON.parse(Buffer.from(b64, "base64").toString());
};
export const Uint8ArrayTob64 = function (u8) {
  var b64 = Buffer.from(u8).toString("base64");
  return b64;
};

// JSON to Uint8Array parsing and visa versa
export const JsonToArray = function (json) {
  return new Uint8Array(Buffer.from(json));
};
function Utf8ArrayToStr(array) {
  let out, i, c;
  let char2, char3;
  out = "";
  const len = array.length;
  i = 0;
  while (i < len) {
    c = array[i++];
    switch (c >> 4) {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
        // 0xxxxxxx
        out += String.fromCharCode(c);
        break;
      case 12:
      case 13:
        // 110x xxxx   10xx xxxx
        char2 = array[i++];
        out += String.fromCharCode((c & 0x1f) << 6 | char2 & 0x3f);
        break;
      case 14:
        // 1110 xxxx  10xx xxxx  10xx xxxx
        char2 = array[i++];
        char3 = array[i++];
        out += String.fromCharCode((c & 0x0f) << 12 | (char2 & 0x3f) << 6 | (char3 & 0x3f) << 0);
        break;
    }
  }
  return out;
}
// Converts A Unit8Array to String
export function Uint8ArrayToJS(data) {
  const decodedData = Utf8ArrayToStr(data);
  return decodedData;
}
export const concatArrayBuffers = (...bufs) => {
  const result = new Uint8Array(bufs.reduce((totalSize, buf) => totalSize + buf.byteLength, 0));
  bufs.reduce((offset, buf) => {
    result.set(buf, offset);
    return offset + buf.byteLength;
  }, 0);
  return result;
};
export const jsonStringToBase64 = jsonString => {
  const base64 = toBase64(JsonToArray(jsonString));
  return base64;
};
export const jsonToBase64 = json => {
  const jsonString = JSON.stringify(json);
  return jsonStringToBase64(jsonString);
};

/**
 * encode a multibase base58-btc multicodec key
 * @param header Uint8Array header for multicodec encoding
 * @param key Uint8Array of key encoding
 */
export const encodeMbKey = (header, key) => {
  const mbKey = new Uint8Array(header.length + key.length);
  mbKey.set(header);
  mbKey.set(key, header.length);
  return MULTIBASE_BASE58BTC_HEADER + base58.encode(mbKey);
};

/**
 * decode a multibase base58-btc multicodec key
 * @param mbKey string multibase base58-btc multicodec key
 */
export const decodeMbKey = (header, mbKey) => {
  const decoded = base58.decode(mbKey.slice(MULTIBASE_BASE58BTC_HEADER.length));
  if (decoded.slice(0, header.length).toString() !== header.toString()) {
    throw new Error("Invalid multibase base58-btc multicodec key");
  }
  return decoded.slice(header.length);
};