import { constants, Contract, BigNumber, utils } from 'ethers';
import { a$ as NATIVE_TOKEN_ADDRESS, b1 as getNativeTokenByChainId } from './index-4b96b6a0.esm.js';

/**
 * Encodes and decodes Contract functions
 * @contract
 * @public
 */
class ContractEncoder {
  constructor(contractWrapper) {
    this.contractWrapper = contractWrapper;
  }

  /**
   * Encodes the given contract function with argument
   * @returns The encoded data
   */
  encode(fn, args) {
    return this.contractWrapper.readContract.interface.encodeFunctionData(fn, args);
  }

  /**
   * Decode encoded call data for a given function
   * @param fn - the function to decode
   * @param encodedArgs - the encoded arguments
   */
  decode(fn, encodedArgs) {
    return this.contractWrapper.readContract.interface.decodeFunctionData(fn, encodedArgs);
  }
  decodeResult(fn, encodedArgs) {
    return this.contractWrapper.readContract.interface.decodeFunctionResult(fn, encodedArgs);
  }
}

function isNativeToken(tokenAddress) {
  return tokenAddress.toLowerCase() === NATIVE_TOKEN_ADDRESS || tokenAddress.toLowerCase() === constants.AddressZero;
}

/**
 *
 * @param provider - The provider to use
 * @param asset - The asset to fetch the metadata for
 * @returns
 * @internal
 */
async function fetchCurrencyMetadata(provider, asset) {
  if (isNativeToken(asset)) {
    const network = await provider.getNetwork();
    const nativeToken = getNativeTokenByChainId(network.chainId);
    return {
      name: nativeToken.name,
      symbol: nativeToken.symbol,
      decimals: nativeToken.decimals
    };
  } else {
    const ERC20MetadataAbi = (await import('@thirdweb-dev/contracts-js/dist/abis/IERC20Metadata.json')).default;
    const erc20 = new Contract(asset, ERC20MetadataAbi, provider);
    const [name, symbol, decimals] = await Promise.all([erc20.name(), erc20.symbol(), erc20.decimals()]);
    return {
      name,
      symbol,
      decimals
    };
  }
}

/**
 *
 * @param providerOrSigner - The provider or signer to use
 * @param asset - The asset to fetch the value for
 * @param price - The price to fetch the value for
 * @returns
 * @internal
 */
async function fetchCurrencyValue(providerOrSigner, asset, price) {
  const metadata = await fetchCurrencyMetadata(providerOrSigner, asset);
  return {
    ...metadata,
    value: BigNumber.from(price),
    displayValue: utils.formatUnits(price, metadata.decimals)
  };
}

export { ContractEncoder as C, fetchCurrencyValue as a, fetchCurrencyMetadata as f, isNativeToken as i };
