import { ethers, Wallet, BigNumber } from 'ethers';

export interface Token {
  contractAddress: string;
  decimals: number;
  symbol: string;
  name: string;
  balance: string;
}
export interface BalanceResult {
  ethereumAddress: string;
  tokens: Token[];
}

export interface IEvmContractParams {
  contractAddress: string;
  abi: any[];
  methodName: string;
  params: any[];
  rpc: string;
  chainId: number;
  gasLimit: string;
  amount?: string;
  nonce?: number;
  maxPriorityFeePerGasValue?: BigNumber;
  maxFeePerGasValue?: BigNumber;
}

export interface IEvmCallDataParams {
  contractAddress: string;
  callData: string;
  rpc: string;
  chainId: number;
  gasLimit: string;
  value?: string;
  maxPriorityFeePerGasValue?: BigNumber;
  maxFeePerGasValue?: BigNumber;
  nonce?: number;
}

export interface IDomain {
  name: string;
  version: string;
  chainId: number;
  verifyingContract: string;
}

export interface ITypes {
  [key: string]: Record<'name' | 'type', string>[];
}

export interface IMessage {
  [key: string]: any;
}

export interface IEvmSignParams {
  contractAddress: string;
  data: string;
  rpc: string;
  chainId: number;
  gasLimit: string;
  amount?: string;
  nonce?: number;
  maxPriorityFeePerGasValue?: BigNumber;
  maxFeePerGasValue?: BigNumber;
}

export interface ITransferToken {
  to: string;
  amount: string;
  rpc: string;
  chainId: number;
  nonce?: number;
  maxPriorityFeePerGasValue?: BigNumber;
  maxFeePerGasValue?: BigNumber;
}

export interface ITransferSolanaNativeToken {
  to: string;
  amount: number;
  rpc: string;
  unitLimit?: number;
  unitPrice?: number;
}

export interface ITransferSolanaToken {
  to: string;
  amount: number | bigint;
  rpc: string;
  contractAddress: string;
  unitLimit?: number;
  unitPrice?: number;
}

export interface ICheckNFT {
  rpc: string;
  contractAddress: string;
}

export interface INativeTokenTransferFee {
  rpc: string;
  chainId: number;
  from: string;
}

export interface IEvmContractMethodFee {
  rpc: string;
  chainId: number;
  contractAddress: string;
  abi: any[];
  methodName: string;
  params: any[];
  from: string;
  amount?: ethers.BigNumber;
}

export interface IFSLWeb3Params {
  mnemonic?: string;
  gasPriorityPolygon?: string;
  gasPriorityExtraPolygon?: string;
  gasPriorityExtraEvm?: string;
}

export declare class FSLWeb3 {
  constructor(params: IFSLWeb3Params);

  static BigNumberFrom: (value: any) => BigNumber;
  static EtherUtils: typeof ethers.utils;
  exportWallet(): Wallet;
  createAccount(): string;
  static toBigInt(value: string): ethers.BigNumberish;
  static isMnemonic(mnemonic: string): boolean;
  static isPrivateKey(privateKey: string): string | null;
  static validateSolAddress(address: string): boolean;
  static getEnsAddress(ensName: string, rpc?: string): Promise<string | null>;
  static lookupEnsName(address: string, rpc?: string): Promise<string | null>;
  static checkContractType(address: string, rpc: string): Promise<string>;
  static getTokenTicker(
    contractAddresses: string,
    rpc: string,
  ): Promise<string>;

  static getUNSOwner(domain: string): Promise<string | null>;
  static getUnstoppableDomains(
    domain: string,
    ticker: string,
    chain?: string,
  ): Promise<string | null>;
  static reverseUnstoppableDomains(address: string): Promise<string | null>;

  static assignPublicKey(obj: Record<string, any> | string): PublicKey;

  generateWallet(mnemonic: string): void;
  transferEvmNativeToken(params: ITransferToken): Promise<string>;

  callEvmContractMethod(params: IEvmContractParams): Promise<string>;

  callEvmContractByCallData(
    params: IEvmCallDataParams,
  ): Promise<ethers.providers.TransactionReceipt>;

  callEvmContractReadMethod(
    rpc: string,
    address: string,
    contractAddresses: string,
    abi: any,
    method: string,
  ): Promise<any>;

  evmSignMessage(msg: string): Promise<string>;

  evmSignTypedData(
    domain: IDomain,
    types: ITypes,
    message: IMessage,
  ): Promise<string>;

  callEvmSignMethod(params: IEvmSignParams): Promise<string>;

  getTransactionNonceCount(rpc: string): Promise<string>;

  sendEvmTransaction(
    signedTx: string,
    rpc: string,
    confirmed?: boolean,
  ): Promise<string>;

  transferSolanaNativeToken(
    params: ITransferSolanaNativeToken,
  ): Promise<string>;

  transferSolanaSplToken(params: ITransferSolanaToken): Promise<string>;

  checkSolanaNFTValid({ rpc, contractAddress }: ICheckNFT): Promise<boolean>;

  getEvmErc20TokenBalance(
    walletAddress: string,
    rpc: string,
    contractAddresses: string[],
  ): Promise<BalanceResult>;

  getEvmNativeTokenBalance(
    walletAddress: string,
    rpc: string,
  ): Promise<BigNumber>;

  calculateEvmNativeTokenTransferGasFee(
    params: INativeTokenTransferFee,
  ): Promise<string>;

  calculateCallEvmContractMethodGasFee(
    params: IEvmContractMethodFee,
  ): Promise<string>;

  getEvmNativeTokenTransactions(
    rpc: string,
    chainId: number,
    from: string,
    blockNum: number,
  ): Promise<any>;

  getEvmErcTokenTransactions(
    rpc: string,
    contractAddress: string,
    abi: string[],
    from: string,
    blockNum: number,
  ): Promise<any>;

  getEvmSwapRouterAmountsOut(
    rpc: string,
    contractAddress: string,
    path: string[],
    amountIn: ethers.BigNumber,
  ): Promise<any>;

  getEvmErc20TokenAllowance(
    rpc: string,
    contractAddress: string,
    from: string,
    to: string,
  ): Promise<BigNumber>;

  getEvmErc20TokenBalanceOf(
    walletAddress: string,
    rpc: string,
    contractAddresses: string,
  ): Promise<BigNumber>;

  checkEvmTransactionHashStatus(
    txHash: string,
    rpc: string,
  ): Promise<ethers.providers.TransactionReceipt>;

  getEvmTransactionBlock(
    blockNum: number,
    rpc: string,
  ): Promise<ethers.providers.Block>;

  checkSolanaTransactionHashStatus(
    txHash: string,
    rpc: string,
  ): Promise<web3.RpcResponseAndContext<web3.SignatureStatus | null>>;

  getSolanaNativeTokenBalance(
    walletAddress: string,
    rpc: string,
  ): Promise<number>;

  getSolanaSplTokenBalance(
    walletAddress: string,
    rpc: string,
    contractAddress: string,
  ): Promise<number>;

  getSolanaTokenTransactions(
    rpc: string,
    from: string,
    limit: number,
  ): Promise<web3.VersionedTransactionResponse[]>;

  getEvmBlockTime(rpc: string, blockNum: number): Promise<number>;

  getSolanaAddress(): string;

  exportSolanaPrivatekey(): string;

  exportPrivateKey(): string;

  exportMnemonic(): Mnemonic;

  getSolanaTokenUnit({
    fromToken,
    toToken,
    rpc,
  }: {
    fromToken: TOKEN_NAME;
    toToken: TOKEN_NAME;
    rpc: string;
  }): promise<string>;

  swapSolanaToken({
    fromToken,
    toToken,
    tokenAmount,
    rpc,
    slipNum,
  }: {
    fromToken: TOKEN_NAME;
    toToken: TOKEN_NAME;
    tokenAmount: number;
    rpc: string;
    slipNum?: number;
  }): promise<string>;

  signSolanaMessage(message: string): Uint8Array;

  static verifySolanaMessage(
    message: string,
    signature: Uint8Array,
    publicKey: PublicKey,
  ): boolean;

  sendSolanaTransaction(
    encodedTransaction: string,
    rpc: string,
  ): Promise<string>;

  signSolanaInstructions(
    instructions: TransactionInstruction[],
    keypairs: Keypair[],
    rpc: string,
    unitLimit?: number,
    unitPrice?: number,
  ): Promise<string>;

  signSolanaTransactionWithBuffers(
    bufferStrs: string[],
    versions: Array<'legacy' | 0>,
  ): string[];

  signSolanaTransaction(
    bufferStrs: string[],
    versions: Array<'legacy' | 0>,
  ): Array<VersionedTransaction | Transaction>;

  getEvmFeeFast(
    rpc: string,
    chainId: number,
  ): Promise<
    | {
        maxPriorityFeePerGas?: undefined;
        maxFeePerGas?: undefined;
      }
    | {
        maxPriorityFeePerGas: ethers.BigNumber;
        maxFeePerGas: ethers.BigNumber;
      }
  >;
}
