import { ethers, BaseContract, BigNumber } from 'ethers';
import { UFOConfig } from './types';
import { Provider } from '@ethersproject/abstract-provider';
import { NETWORK_ID, RPCS } from './constants/constants';
import ufoABI from './abis/ufoABI.json';
import ufoLPABI from './abis/ufoLPABI.json';
import plasmaABI from './abis/ufoLPABI.json';
import uapABI from './abis/uapABI.json';
import erc20 from './abis/ERC20.json';
const ufoAbi = JSON.stringify(ufoABI);
const ufoLPAbi = JSON.stringify(ufoLPABI);
const plasmaAbi = JSON.stringify(plasmaABI);
const uapAbi = JSON.stringify(uapABI);
const usdtAbi = JSON.stringify(erc20.abi);
export class ufoProviderSDK {
  private ufo: BaseContract = null;
  private ufoLP: BaseContract = null;
  private plasma: BaseContract = null;
  private uap: BaseContract = null;
  private weth: BaseContract = null;
  private usdt: BaseContract = null;
  private provider: Provider = null;
  constructor(provider: Provider, ufoConfig: UFOConfig, netID: number) {
    this.provider = provider;
    switch (netID) {
      case NETWORK_ID.ETHEREUM:
      case NETWORK_ID.SEPOLIA:
      default:
        this.ufo = new ethers.Contract(ufoConfig.ufoTokenOnEth, ufoAbi, provider);
        this.ufoLP = new ethers.Contract(ufoConfig.ufoLPTokenOnEth, ufoLPAbi, provider);
        this.weth = new ethers.Contract(ufoConfig.WETHOnEth, uapAbi, this.provider);
        if (ufoConfig.plasmaTokenOnEth != undefined) {
          this.plasma = new ethers.Contract(ufoConfig.plasmaTokenOnEth, plasmaAbi, provider);
        }
        break;
      case NETWORK_ID.BEAM_TESTNET:
      case NETWORK_ID.BEAM:
        this.ufo = new ethers.Contract(ufoConfig.ufoTokenOnBeamTestNet, ufoAbi, provider);
        this.ufoLP = new ethers.Contract(ufoConfig.ufoLPTokenOnBeamTestNet, ufoLPAbi, provider);
        this.plasma = new ethers.Contract(ufoConfig.plasmaTokenOnBeamTestNet, plasmaAbi, provider);
        this.uap = new ethers.Contract(ufoConfig.uapOnBeamTestNet, uapAbi, this.provider);
        this.weth = new ethers.Contract(ufoConfig.WETHOnBeamTestNet, uapAbi, this.provider);
        this.usdt = new ethers.Contract(ufoConfig.usdtTokenOnBeamTestNet, usdtAbi, this.provider);
        break;
    }
  }

  public async getUFOTotalSupply(): Promise<string> {
    let totalSupply = await this.ufo.functions.totalSupply();
    let decimals = await this.ufo.functions.decimals();
    let count = BigNumber.from(totalSupply.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getUFOLPTotalSupply(): Promise<string> {
    let totalSupply = await this.ufoLP.functions.totalSupply();
    let decimals = await this.ufoLP.functions.decimals();
    let count = BigNumber.from(totalSupply.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getUFOCount(address: string): Promise<string> {
    let balance = await this.ufo.functions.balanceOf(address);
    let decimals = await this.ufo.functions.decimals();
    let count = BigNumber.from(balance.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getUAPBalance(address: string): Promise<string> {
    let balance = await this.uap.functions.balanceOf(address);
    let decimals = await this.uap.functions.decimals();
    let count = BigNumber.from(balance.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getUFOLPCount(address: string): Promise<string> {
    let balance = await this.ufoLP.functions.balanceOf(address);
    let decimals = await this.ufoLP.functions.decimals();
    let count = BigNumber.from(balance.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getPlasmaCount(address: string): Promise<string> {
    if (this.plasma == null) {
      return '0';
    }
    let balance = await this.plasma.functions.balanceOf(address);
    let decimals = await this.plasma.functions.decimals();
    let count = BigNumber.from(balance.toString()).div(BigNumber.from('10').pow(decimals));
    return count.toString();
  }

  public async getNativeTokenBalance(address: string): Promise<string> {
    let balance = await this.provider.getBalance(address);
    let actual = ethers.utils.formatEther(balance.toString());
    return actual.toString();
  }

  public async getInfoOfMaticByPromise(address: string): Promise<any> {
    let contractCalls = [this.ufo, this.ufoLP, this.plasma, this.uap, this.weth, this.usdt];
    const res = await Promise.all(contractCalls.map((item) => item.functions.balanceOf(address)));
    const nativeBalance = await this.provider.getBalance(address);
    const usdtDecimal = await this.usdt.functions.decimals();
    return {
      ufo: ethers.utils.formatEther(res[0][0].toString()),
      ufoLP: ethers.utils.formatEther(res[1][0].toString()),
      plasma: ethers.utils.formatEther(res[2][0].toString()),
      uap: ethers.utils.formatEther(res[3][0].toString()),
      nativeCrypto: ethers.utils.formatEther(nativeBalance.toString()),
      wEth: ethers.utils.formatEther(res[4][0].toString()),
      usdt: ethers.utils.formatUnits(res[5][0].toString(), usdtDecimal),
    };
  }
}
