/**
 * @internal
 */
export type ChainName =
  | "other"
  | "mainnet"
  | "fantom"
  | "avalanche"
  | "moonriver"
  | "polygon"
  | "arbitrum"
  | "celo"
  | "goerli"
  | "phuture"
  | "optimism"
  | "binance"
  | "aurora"
  | "base"

export type ChainId =
  | 1
  | 250
  | 43114
  | 42161
  | 5
  | 1285
  | 137
  | 42220
  | 1338
  | 10
  | 56
  | 15366
  | 15367
  | 1313161554
  | 8453
  | number

export type TokenAllowanceApiParams = {
  chain_id: string
  account_address: string
  token_address?: string
  from_token: string
  to_token: string
  token_id?: string
  to_chain_id?: string
}

export type TokenAllowanceRequest = {
  /**
   * Alias for `fromChainId`. This will be deprecated in the future: use `fromChainId`.
   */
  chainId?: ChainId
  accountAddress: Web3Address
  /**
   * Alias for `fromToken`. This will be deprecated in the future: use `fromToken`.
   *
   * @deprecated in favor of `fromToken`. This parameter will be removed in the future, please migrate.
   */
  tokenAddress?: Web3Address
  /**
   * ChainId of `fromToken`.
   * See https://chainlist.org/.
   */
  fromChainId?: ChainId
  /**
   * Address of `fromToken`, the token you wish to zap with.
   */
  fromToken: Web3Address
  /**
   * ChainId of `toToken`.
   * See https://chainlist.org/.
   */
  toChainId: ChainId
  /**
   * Address of `toToken`, the token you wish to zap into.
   */
  toToken: Web3Address
  /**
   * ERC-721 tokenId.
   */
  tokenId?: string
}

export type TokenAllowanceResult = {
  allowance: string
  spender: Web3Address
}

export type StatusRequest = {
  chainId: ChainId
  txHash: string
}

export type StatusApiParams = {
  chain_id: string
  tx_hash?: string
}

export type StatusApiResponse = {
  status: string
  substatus: string
  substatus_message: string
  to_tx_hash: string
  to_chain_id?: string
}

export type StatusResult = {
  status: string
  substatus: string
  substatusMessage: string
  toTxHash: string
  toChainId?: string
}

export type ApproveApiParams = {
  chain_id: string
  token_address?: string
  from_token: string
  to_token: string
  amount?: string
  token_id?: string
  to_chain_id?: string
}

export type ApproveRequest = {
  /**
   * Alias for `fromChainId`. This will be deprecated in the future: use `fromChainId`.
   */
  chainId?: ChainId
  /**
   * Alias for `fromToken`.
   *
   * @deprecated in favor of `fromToken`. This parameter will be removed in the future, please migrate.
   */
  tokenAddress?: Web3Address
  /**
   * ChainId of `fromToken`.
   * See https://chainlist.org/.
   */
  fromChainId?: ChainId
  /**
   * Address of `fromToken`, the token you wish to zap with.
   */
  fromToken: Web3Address
  /**
   * ChainId of `toToken`.
   * See https://chainlist.org/.
   */
  toChainId: ChainId
  /**
   * Address of `toToken`, the token you wish to zap into.
   */
  toToken: Web3Address
  /**
   * @default "115792089237316195423570985008687907853269984665640564039457584007913129639935"
   */
  amount?: string
  /**
   * ERC-721 tokenId.
   */
  tokenId?: string
}

export type ApproveResult = {
  /**
   * Contract address where the unsigned transaction needs to be sent.
   */
  to: Web3Address
  /**
   * Unsigned transaction data.
   */
  data: string
}

export type ContractAddressApiParams = {
  chain_id: string
  from_token: string
  to_token: string
  to_chain_id: string
}

export type WidoSpenderRequest = {
  /**
   * ChainId of `fromToken`.
   * See https://chainlist.org/.
   */
  chainId: ChainId
  /**
   * Address of `fromToken`, the token you wish to zap with.
   */
  fromToken: Web3Address
  /**
   * Address of `toToken`, the token you wish to zap into.
   */
  toToken: Web3Address
  /**
   * ChainId of the `to_token`.
   * See https://chainlist.org/.
   */
  toChainId: ChainId
}

export enum GaslessType {
  ERC4337 = "erc4337",
  EOA = "eoa",
}

export enum Providers {
  LiFi = "LiFi",
  ZeroEx = "ZeroEx",
  OpenOcean = "OpenOcean",
}

export type QuoteRequest = {
  /**
   * ChainId of `fromToken`.
   * See https://chainlist.org/.
   */
  fromChainId: ChainId
  /**
   * Address of `fromToken`, the token you wish to zap with.
   */
  fromToken: Web3Address
  /**
   * ChainId of the `to_token`.
   * See https://chainlist.org/.
   */
  toChainId: ChainId
  /**
   * Address of the to token.
   */
  toToken: Web3Address
  /**
   * Amount of the `fromToken` to spend on the user's behalf.
   */
  amount?: string
  /**
   * Address of user placing the order.
   * Required to receive a valid unsigned tx.
   */
  user?: Web3Address
  /**
   * The maximum acceptable slippage of the `to_token` amount.
   * A number between `0` and `1`.
   * E.g.: `0.01` for 1% slippage tolerance.
   *
   * @default 0.01
   */
  slippagePercentage?: number
  /**
   * Address of where the zapped funds should be sent after the order executes.
   */
  recipient?: Web3Address
  varsOverride?: Record<string, number | string | unknown>
  /**
   * Address of partner referring the user.
   */
  partner?: Web3Address
  /**
   * For Uniswap V3 zaps.
   */
  lowerTick?: Web3Address
  /**
   * For Uniswap V3 zaps.
   */
  upperTick?: Web3Address
  /**
   * ERC-721 tokenId.
   */
  tokenId?: string
  /**
   * Gas-less type of transaction
   */
  gaslessType?: GaslessType
  /**
   * Specific swap providers
   */
  providers?: Providers[]
}

/**
 * @internal
 */
export type QuoteApiParams = {
  from_chain_id: string
  from_token: string
  to_chain_id: string
  to_token: string
  amount?: string
  user?: string
  slippage_percentage?: string
  partner?: string
  lower_tick?: string
  upper_tick?: string
  token_id?: string
  recipient?: string
  gasless_type?: string
  providers?: string
}

/**
 * @internal
 */
export type QuoteApiResponse = {
  is_supported: boolean
  steps: Step[]
  steps_count: number
  //
  price: string
  min_price: string
  from_token_usd_price: string
  from_token_amount: string
  from_token_amount_usd_value: string
  to_token_usd_price: string
  to_token_amount: string
  to_token_amount_usd_value: string
  min_to_token_amount: string
  expected_slippage: string
  from: Web3Address
  to: Web3Address
  value: string
  data: string
  messages?: { type: "info" | "warning"; message: string }[]
  gas_fee?: string
  gas_fee_usd?: string
  fee_bps?: number
  fee_in_from_token?: number
  bridge_fee_usd_value?: string
  fee_usd_value?: string
}

export type QuoteResult = {
  /**
   * Whether the route is supported or not.
   */
  isSupported: boolean
  /**
   * The steps this route will take. Used to show the route breakdown.
   */
  steps: {
    protocol: string
    chainId: ChainId
    toChainId: ChainId
    fromToken: Web3Address
    toToken: Web3Address
    swapAddress: Web3Address
    functionName: string
  }[]
  /**
   * Number of steps the route will take.
   */
  stepsCount: number
  /**
   * Expected price of `toToken`.
   */
  price?: string
  /**
   * Minimum accepted price for a successful transaction.
   */
  minPrice?: string
  /**
   * Price of `fromToken` in US dollars.
   */
  fromTokenUsdPrice?: string
  /**
   * Amount of `fromToken` to send.
   */
  fromTokenAmount?: string
  /**
   * Value of `fromTokenAmount` in US dollars.
   */
  fromTokenAmountUsdValue?: string
  /**
   * Price of `toToken` in US dollars.
   */
  toTokenUsdPrice?: string
  /**
   * Expected amount of `toToken` to receive.
   */
  toTokenAmount?: string
  /**
   * Value of `toTokenAmount` in US dollars.
   */
  toTokenAmountUsdValue?: string
  /**
   * Expected slippage calculated from `fromTokenAmountUsdValue` and `toTokenAmountUsdValue`.
   * If the value returned is < 0, the zap is expected to result in positive slippage.
   */
  expectedSlippage?: string
  /**
   * Minimum amount of the to token the user is willing to accept for a successful transaction.
   */
  minToTokenAmount?: string
  /**
   * User address who should be sending the tx.
   */
  from?: Web3Address
  /**
   * Contract address where the unsigned transaction needs to be sent.
   */
  to?: Web3Address
  /**
   * Unsigned transaction data.
   */
  data?: string
  /**
   * Amount of native tokens that need to be sent.
   */
  value?: string
  messages: { type: "info" | "warning"; message: string }[]
  gasFee?: string
  gasFeeUsdValue?: string
  feeBps?: string
  /**
   * Service fee denoted in the 'from' token units
   */
  feeInFromToken?: number
  /**
   * Bridge fee value in US dollars.
   */
  bridgeFeeUsdValue?: string
  /**
   * Service fee value in US dollars.
   */
  feeUsdValue?: string
}

/**
 * @internal
 */
export type Order = {
  user: Web3Address
  fromToken: Web3Address
  fromChainId: ChainId
  toToken: Web3Address
  toChainId: ChainId
  fromTokenAmount: string
  minToTokenAmount: string
  nonce: number
  expiration: number
}

/**
 * @internal
 */
export type Step = {
  protocol: string
  chainId: ChainId
  toChainId: ChainId
  fromToken: Web3Address
  toToken: Web3Address
  swapAddress: Web3Address
  functionName: string
}

/**
 * @internal
 */
export type ConfigType = {
  WIDO_API_URL: string
  DEBUG: boolean
  SEGMENT_KEY: string
}

export type SupportedTokensApiParams = {
  include_pricing?: string
  include_preview?: string
  to_chain_id?: string
  to_token?: string
}

export type SupportedTokensRequest = {
  /**
   * Filter by `chainId`.
   *
   * @default []
   */
  chainId?: ChainId[]
  /**
   * Filter by `protocol`.
   *
   * @default []
   */
  protocol?: Protocol[]
  /**
   * Whether to include pricing.
   *
   * @default false
   */
  includePricing?: boolean
  /**
   * Address of `toToken`, the token you wish to zap into.
   * Use this if you'd like to receive a list of tokens you can zap in with.
   */
  toToken?: Web3Address
  /**
   * ChainId of the `to_token`.
   * See https://chainlist.org/.
   */
  toChainId?: ChainId
}

export type Token = {
  address: Web3Address
  chainId: ChainId
  protocol: Protocol
  /**
   * @default "0.0"
   */
  usdPrice: string
  symbol: string
  name: string
  decimals: number
  logoURI: string
}

export type Balance = {
  address: Web3Address
  chainId: ChainId
  protocol: Protocol
  /**
   * @default "0.0"
   */
  usdPrice: string
  symbol: string
  name: string
  decimals: number
  logoURI: string
  balance: string
  balanceUsdValue: string
}

/**
 * @internal
 */
export type WidoContractApiResponse = {
  spender: Web3Address
  err?: string
}

export type ErrorCode = "SERVER_ERR" | "INVALID_REQUEST" | string
export type ValidationError = {
  loc: string[]
  msg: string
  type: string
}

/**
 * @internal
 */
export type ErrorApiResponse = {
  code: ErrorCode
  detail: string
  validationErrors: ValidationError[]
}

/**
 * @internal
 */
export type PaymasterApiRequest = {
  chainId: ChainId
  sender: string
  nonce: number
  initCode: string
  callData: string
  callGasLimit: number
  verificationGasLimit: number
  preVerificationGas: number
  maxFeePerGas: number
  maxPriorityFeePerGas: number
  paymasterAndData: string
  signature: string
}

/**
 * @internal
 */
export type PaymasterApiResponse = {
  paymasterAndData: string
}

/**
 * Example: `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`
 */
export type Web3Address = string

export type Protocol =
  | "curve.fi"
  | "aave.com"
  | "yearn.finance"
  | "sturdy.finance"
  | "pickle.finance"
  | "dex"
  | "unknown"
  | string
