// Copyright (C) 2020-2022 Notus Network
//
// Notus Network is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

import {BN} from 'bn.js';
import {
  NetworkLayer,
  NetworkType,
  PortNo,
  ListMainNodeIp,
  Bip39WordArray,
  Default_WordListArrayCount,
  CommonDelimeterChar,
} from '../types';
import {Md5Hash, Sha1Hash} from './hash';

export function GetNetworkPort(
  NetworkLayer: NetworkLayer,
  NetworkType: NetworkType,
): number {
  return PortNo[NetworkLayer][NetworkType];
}

export function MakeHttpListenerPath(
  ipAddress: string,
  port: string,
  UseSSL: boolean = false,
): string {
  return 'http' + (UseSSL ? 's' : '') + '://' + ipAddress + ':' + port + '/';
}

export async function FindAvailableNode(
  url: string,
  NetworkType: NetworkType,
  Networklayer: NetworkLayer,
  isSsl: boolean = false,
): Promise<string> {
  let res = '';
  if (isSsl) {
    if (NetworkType === 30)
      res = await GetRequest('https://devnet.notus.network/' + url);
    else if (NetworkType === 20)
      res = await GetRequest('https://testnet.notus.network/' + url);
    else if (NetworkType === 10)
      res = await GetRequest('https://mainnet.notus.network/' + url);
    else throw new Error('Invalid Network Type');
  } else {
    for (let a = 0; a < ListMainNodeIp.length; a++) {
      try {
        res = await GetRequest(
          MakeHttpListenerPath(
            ListMainNodeIp[a],
            GetNetworkPort(Networklayer, NetworkType).toString(),
          ) + url,
        );
      } catch (ex) {
        continue;
      }
    }
  }
  return res;
}

export function GetRequest(url: string): Promise<string> {
  return fetch(url)
    .then(async response => {
      if (!response.ok) {
        throw new Error(response.statusText);
      }
      return JSON.stringify(await response.json());
    })
    .catch(ex => {
      console.log(ex);
      return '';
    });
}

export function PostRequest<T>(url: string, object: T): Promise<string> {
  return fetch(url, {
    method: 'POST',
    // x-www-form-urlencoded
    body: new URLSearchParams({
      data: JSON.stringify(object),
    }),
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  })
    .then(async response => {
      if (!response.ok) {
        throw new Error(response.statusText);
      }
      return JSON.stringify(await response.json());
    })
    .catch(ex => {
      console.log(ex);
      return '';
    });
}

export function SeedPhraseList(): string[] {
  var wordList: string[] = [];
  for (var i = 0; i < Default_WordListArrayCount; i++) {
    wordList[i] = Bip39Keyword(
      parseInt(
        new BN(
          Sha1Hash(
            new Date().toLocaleTimeString() +
              Md5Hash(
                new Date().toLocaleString() +
                  getRandomInt(10000000, Number.MAX_SAFE_INTEGER).toString(),
              ),
          ),
          16,
        )
          .toString(10)
          .substring(0, 4),
      ),
    );
  }

  return wordList;
}

export function Bip39Keyword(Bip39WordIndexNo: number): string {
  Bip39WordIndexNo = Math.abs(Bip39WordIndexNo);

  while (true) {
    if (Bip39WordArray.length > Bip39WordIndexNo) {
      break;
    } else {
      Bip39WordIndexNo -= Bip39WordArray.length;
    }
  }

  return Bip39WordArray[Bip39WordIndexNo];
}

function getRandomInt(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

export function Bip39KeywordDoesExist(
  keyword: string,
  indexNo: number = -1,
): Boolean {
  if (indexNo != -1) return Bip39WordArray[indexNo] == keyword;
  else return Bip39WordArray.indexOf(keyword) != -1;
}

export function MergeRawDataWithCommonDelimeterChar(...args: any[]): string {
  let res = '';
  for (let a = 0; a < args.length; a++) {
    res += args[a];
    if (a != args.length - 1) res += CommonDelimeterChar;
  }
  return res;
}
