import {PublicKey} from "@chainsafe/blst";
import {fromHexString} from "@chainsafe/ssz";

/**
 * 0x prefix a string if not prefixed already
 */
export function ensure0xPrefix(hex: string): string {
  if (!hex.startsWith("0x")) hex = `0x${hex}`;
  return hex;
}

export function isValidatePubkeyHex(pubkeyHex: string): boolean {
  return /^0x[0-9a-fA-F]{96}$/.test(pubkeyHex);
}

export function getPubkeyHexFromKeystore(keystore: {pubkey?: string}): string {
  if (!keystore.pubkey) {
    throw Error("Invalid keystore, must contain .pubkey property");
  }

  const pubkeyHex = ensure0xPrefix(keystore.pubkey);
  if (!isValidatePubkeyHex(pubkeyHex)) {
    throw Error(`Invalid keystore pubkey format ${pubkeyHex}`);
  }

  return pubkeyHex;
}

/**
 * Parse string inclusive range: `0..32`, into an array of all values in that range
 */
export function parseRange(range: string): number[] {
  if (!range.includes("..")) {
    throw Error(`Invalid range '${range}', must include '..'`);
  }

  const [from, to] = range.split("..").map((n) => parseInt(n));

  if (isNaN(from)) throw Error(`Invalid range from isNaN '${range}'`);
  if (isNaN(to)) throw Error(`Invalid range to isNaN '${range}'`);
  if (from > to) throw Error(`Invalid range from > to '${range}'`);

  const arr: number[] = [];
  for (let i = from; i <= to; i++) {
    arr.push(i);
  }

  return arr;
}

export function assertValidPubkeysHex(pubkeysHex: string[]): void {
  for (const pubkeyHex of pubkeysHex) {
    const pubkeyBytes = fromHexString(pubkeyHex);
    PublicKey.fromBytes(pubkeyBytes, true);
  }
}

/**
 * Parses a file to get a list of bootnodes for a network.
 * Bootnodes file is expected to contain bootnode ENR's concatenated by newlines, or commas for
 * parsing plaintext, YAML, JSON and/or env files.
 */
export function parseBootnodesFile(bootnodesFile: string): string[] {
  const enrs = [];
  for (const line of bootnodesFile.trim().split(/\r?\n/)) {
    for (const entry of line.split(",")) {
      const sanitizedEntry = entry.replace(/['",[\]{}.]+/g, "").trim();

      if (sanitizedEntry.includes("enr:-")) {
        const parsedEnr = `enr:-${sanitizedEntry.split("enr:-")[1].split("#")[0].trim()}`;
        enrs.push(parsedEnr);
      }
    }
  }
  return enrs;
}
