// 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 {
  NetworkLayer,
  NetworkType,
  CurrencyList,
  WalletBalanceStruct,
  CryptoTransactionResult,
  BlockStatusCode,
  LockAccountStruct,
  ListMainNodeIp,
  BlockResponse,
  MultiWalletStruct,
  MultiWalletTransactionApproveStruct,
} from '../types';
import {
  FindAvailableNode,
  GetNetworkPort,
  MakeHttpListenerPath,
  MergeRawDataWithCommonDelimeterChar,
  PostRequest,
  signMessage,
} from '../core';

/**
 * Gets currency list from the network
 *
 * @param {NetworkType} networkType - Network type (MainNet:10, TestNet:20, DevNet:30)
 * @returns Currency list
 */
export async function GetCurrencyList(
  currentNetwork: NetworkType,
): Promise<CurrencyList[]> {
  let res: CurrencyList[] = await JSON.parse(
    await FindAvailableNode(
      'currency/list/',
      currentNetwork,
      NetworkLayer.Layer1,
      true,
    ),
  );
  return res;
}

/**
 * Gets balance of the wallet
 * @param {string} walletKey - Wallet key
 * @param {NetworkType} currentNetwork - Network type (MainNet:10, TestNet:20, DevNet:30)
 * @returns Balance of the wallet
 */
export async function GetBalance(
  walletKey: string,
  currentNetwork: NetworkType,
) {
  let res: WalletBalanceStruct = await JSON.parse(
    await FindAvailableNode(
      'balance/' + walletKey + '/',
      currentNetwork,
      NetworkLayer.Layer1,
      true,
    ),
  );
  return res.Balance;
}

export async function Airdrop(walletKey: string, currentNetwork: NetworkType) {
  let res: CryptoTransactionResult = await JSON.parse(
    await FindAvailableNode(
      'airdrop/' + walletKey + '/',
      currentNetwork,
      NetworkLayer.Layer1,
      true,
    ),
  );
  return res;
}

export async function GetStatus(
  BlockUid: string,
  currentNetwork: NetworkType,
  currentLayer: NetworkLayer,
) {
  let res: BlockStatusCode = await JSON.parse(
    await FindAvailableNode(
      'status/' + BlockUid + '/',
      currentNetwork,
      currentLayer,
      true,
    ),
  );
  return res;
}

/*
export interface LockAccountStruct {
  UID: string;
  WalletKey: string;
  UnlockTime: number;
  PublicKey: string;
  Sign: string;
}

let exitInnerLoop = false;
    while (!exitInnerLoop) {
      for (let a = 0; a < ListMainNodeIp.length && !exitInnerLoop; a++) {
        let nodeIpAddress = '';
        if (nodeIp == '') nodeIpAddress = ListMainNodeIp[a];
        else nodeIpAddress = nodeIp;

        try {
          let fullUrlAddress = '';
          if (isSsl) {
            fullUrlAddress = 'https://devnet.notus.network/send';
          } else {
            fullUrlAddress = MakeHttpListenerPath(
              nodeIpAddress,
              GetNetworkPort(NetworkLayer.Layer1, currentNetwork).toString() +
                '/send',
            );
          }

          const ResultStr = await PostRequest(fullUrlAddress, preTransfer);

          const tmpResultStr: CryptoTransactionResult = JSON.parse(ResultStr);
          exitInnerLoop = true;
          return tmpResultStr;
        } catch (err) {
          console.log(err);
          exitInnerLoop = true;
        }

        if (nodeIp != '') {
          return {
            ID: '',
            Result: BlockStatusCode.AnErrorOccurred,
          };
        }
      }
    }
*/

export async function LockWallet(
  LockAccountStruct: LockAccountStruct,
  privateKey: string,
  isSsl: boolean = false,
  currentNetwork: NetworkType,
) {
  let exitInnerLoop = false;
  while (!exitInnerLoop) {
    for (let a = 0; a < ListMainNodeIp.length && !exitInnerLoop; a++) {
      let nodeIpAddress = ListMainNodeIp[a];

      try {
        let fullUrlAddress = '';
        if (isSsl) {
          fullUrlAddress = 'https://devnet.notus.network/lock/';
        } else {
          fullUrlAddress = MakeHttpListenerPath(
            nodeIpAddress,
            GetNetworkPort(NetworkLayer.Layer1, currentNetwork).toString() +
              '/lock/',
          );
        }

        if (LockAccountStruct.Sign == null)
          LockAccountStruct.Sign = signMessage(
            MergeRawDataWithCommonDelimeterChar(
              LockAccountStruct.UID,
              LockAccountStruct.WalletKey,
              LockAccountStruct.UnlockTime,
              LockAccountStruct.PublicKey,
            ),
            privateKey,
          ).signature;

        const ResultStr = await PostRequest(fullUrlAddress, LockAccountStruct);

        const tmpResultStr: BlockResponse = await JSON.parse(ResultStr);
        exitInnerLoop = true;
        return tmpResultStr;
      } catch (err) {
        console.log(err);
        exitInnerLoop = true;
      }

      if (nodeIpAddress != '') {
        return {
          ID: '',
          Result: BlockStatusCode.AnErrorOccurred,
        };
      }
    }
  }

  return {
    ID: '',
    Result: BlockStatusCode.AnErrorOccurred,
  };
}

export async function GenerateMultiSignAddress(
  MultiWalletStruct: MultiWalletStruct,
  privateKey: string,
  isSsl: boolean = false,
  currentNetwork: NetworkType,
) {
  let exitInnerLoop = false;
  while (!exitInnerLoop) {
    for (let a = 0; a < ListMainNodeIp.length && !exitInnerLoop; a++) {
      let nodeIpAddress = ListMainNodeIp[a];

      try {
        let fullUrlAddress = '';
        if (isSsl) {
          fullUrlAddress = 'https://devnet.notus.network/multi/wallet/add/';
        } else {
          fullUrlAddress = MakeHttpListenerPath(
            nodeIpAddress,
            GetNetworkPort(NetworkLayer.Layer1, currentNetwork).toString() +
              '/multi/wallet/add/',
          );
        }

        if (MultiWalletStruct.Sign == null)
          MultiWalletStruct.Sign = signMessage(
            MergeRawDataWithCommonDelimeterChar(
              MultiWalletStruct.Founder,
              MultiWalletStruct.MultiWalletKey,
              MultiWalletStruct.MultiWalletType,
              MultiWalletStruct.WalletList,
            ),
            privateKey,
          ).signature;

        const ResultStr = await PostRequest(fullUrlAddress, MultiWalletStruct);

        const tmpResultStr: BlockResponse = await JSON.parse(ResultStr);
        exitInnerLoop = true;
        return tmpResultStr;
      } catch (err) {
        console.log(err);
        exitInnerLoop = true;
      }

      if (nodeIpAddress != '') {
        return {
          ID: '',
          Result: BlockStatusCode.AnErrorOccurred,
        };
      }
    }
  }

  return {
    ID: '',
    Result: BlockStatusCode.AnErrorOccurred,
  };
}

export async function ApproveMultiSend(
  MultiSendStruct: MultiWalletTransactionApproveStruct,
  privateKey: string,
  isSsl: boolean = false,
  currentNetwork: NetworkType,
) {
  let exitInnerLoop = false;
  while (!exitInnerLoop) {
    for (let a = 0; a < ListMainNodeIp.length && !exitInnerLoop; a++) {
      let nodeIpAddress = ListMainNodeIp[a];

      try {
        let fullUrlAddress = '';
        if (isSsl) {
          fullUrlAddress =
            'https://devnet.notus.network/multi/transaction/approve/';
        } else {
          fullUrlAddress = MakeHttpListenerPath(
            nodeIpAddress,
            GetNetworkPort(NetworkLayer.Layer1, currentNetwork).toString() +
              '/multi/stransaction/approve/',
          );
        }

        if (MultiSendStruct.Sign == null)
          MultiSendStruct.Sign = signMessage(
            MergeRawDataWithCommonDelimeterChar(
              MultiSendStruct.Approve,
              MultiSendStruct.TransactionId,
              MultiSendStruct.CurrentTime,
              MultiSendStruct.PublicKey,
            ),
            privateKey,
          ).signature;

        const ResultStr = await PostRequest(fullUrlAddress, MultiSendStruct);

        const tmpResultStr: BlockResponse = await JSON.parse(ResultStr);
        exitInnerLoop = true;
        return tmpResultStr;
      } catch (err) {
        console.log(err);
        exitInnerLoop = true;
      }

      if (nodeIpAddress != '') {
        return {
          ID: '',
          Result: BlockStatusCode.AnErrorOccurred,
        };
      }
    }
  }

  return {
    ID: '',
    Result: BlockStatusCode.AnErrorOccurred,
  };
}
