import { Fraction, TradeType } from '@uniswap/sdk-core'
import { BigNumber } from 'ethers/lib/ethers'
import { Trans } from 'i18n'
import JSBI from 'jsbi'

import { nativeOnChain } from '../../constants/tokens'
import { useCurrency, useToken } from '../../hooks/Tokens'
import useENSName from '../../hooks/useENSName'
import { VoteOption } from '../../state/governance/types'
import {
  AddLiquidityV2PoolTransactionInfo,
  AddLiquidityV3PoolTransactionInfo,
  ApproveTransactionInfo,
  ClaimTransactionInfo,
  CollectFeesTransactionInfo,
  CreateV3PoolTransactionInfo,
  DelegateTransactionInfo,
  ExactInputSwapTransactionInfo,
  ExactOutputSwapTransactionInfo,
  ExecuteTransactionInfo,
  MigrateV2LiquidityToV3TransactionInfo,
  QueueTransactionInfo,
  RemoveLiquidityV3TransactionInfo,
  SendTransactionInfo,
  TransactionInfo,
  TransactionType,
  VoteTransactionInfo,
  WrapTransactionInfo,
} from '../../state/transactions/types'

function formatAmount(amountRaw: string, decimals: number, sigFigs: number): string {
  return new Fraction(amountRaw, JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(decimals))).toSignificant(sigFigs)
}

function FormattedCurrencyAmount({
  rawAmount,
  symbol,
  decimals,
  sigFigs,
}: {
  rawAmount: string
  symbol: string
  decimals: number
  sigFigs: number
}) {
  return (
    <>
      {formatAmount(rawAmount, decimals, sigFigs)} {symbol}
    </>
  )
}

function FormattedCurrencyAmountManaged({
  rawAmount,
  currencyId,
  sigFigs = 6,
}: {
  rawAmount: string
  currencyId: string
  sigFigs: number
}) {
  const currency = useCurrency(currencyId)
  return currency ? (
    <FormattedCurrencyAmount
      rawAmount={rawAmount}
      decimals={currency.decimals}
      sigFigs={sigFigs}
      symbol={currency.symbol ?? '???'}
    />
  ) : null
}

function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransactionInfo }) {
  const { ENSName } = useENSName()
  const name = ENSName ?? recipient
  return typeof uniAmountRaw === 'string' ? (
    <Trans
      i18nKey="account.transactionSummary.claimFor"
      components={{
        currency: <FormattedCurrencyAmount rawAmount={uniAmountRaw} symbol="UNI" decimals={18} sigFigs={4} />,
      }}
      values={{
        name,
      }}
    />
  ) : (
    <Trans i18nKey="account.transactionSummary.claimReward" values={{ name }} />
  )
}

function SubmitProposalTransactionSummary() {
  return <Trans i18nKey="account.transactionSummary.submitProposal"></Trans>
}

function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) {
  const token = useToken(info.tokenAddress)

  return BigNumber.from(info.amount)?.eq(0) ? (
    <Trans i18nKey="account.transactionSummary.revoke" values={{ sym: token?.symbol }} />
  ) : (
    <Trans i18nKey="account.transactionSummary.approve" values={{ sym: token?.symbol }} />
  )
}

function VoteSummary({ info }: { info: VoteTransactionInfo }) {
  const proposalKey = `${info.governorAddress}/${info.proposalId}`
  if (info.reason && info.reason.trim().length > 0) {
    switch (info.decision) {
      case VoteOption.For:
        return <Trans i18nKey="account.transactionSummary.vote.for" values={{ proposalKey }} />
      case VoteOption.Abstain:
        return <Trans i18nKey="account.transactionSummary.vote.abstain" values={{ proposalKey }} />
      case VoteOption.Against:
        return <Trans i18nKey="account.transactionSummary.vote.against" values={{ proposalKey }} />
    }
  } else {
    switch (info.decision) {
      case VoteOption.For:
        return <Trans i18nKey="account.transactionSummary.decision.for" values={{ proposalKey, reason: info.reason }} />
      case VoteOption.Abstain:
        return (
          <Trans i18nKey="account.transactionSummary.decision.abstain" values={{ proposalKey, reason: info.reason }} />
        )
      case VoteOption.Against:
        return (
          <Trans i18nKey="account.transactionSummary.decision.against" values={{ proposalKey, reason: info.reason }} />
        )
    }
  }
}

function QueueSummary({ info }: { info: QueueTransactionInfo }) {
  const proposalKey = `${info.governorAddress}/${info.proposalId}`
  return <Trans i18nKey="account.transactionSummary.queueProposal" values={{ proposalKey }} />
}

function ExecuteSummary({ info }: { info: ExecuteTransactionInfo }) {
  const proposalKey = `${info.governorAddress}/${info.proposalId}`
  return <Trans i18nKey="account.transactionSummary.executeProposal" values={{ proposalKey }} />
}

function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInfo }) {
  const { ENSName } = useENSName(delegatee)
  const name = ENSName ?? delegatee
  return <Trans i18nKey="account.transactionSummary.delegateSummary" values={{ name }} />
}

function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) {
  const native = chainId ? nativeOnChain(chainId) : undefined

  if (unwrapped) {
    return (
      <Trans
        i18nKey="account.transactionSummary.unwrapTo"
        components={{
          amount: (
            <FormattedCurrencyAmount
              rawAmount={currencyAmountRaw}
              symbol={native?.wrapped?.symbol ?? 'WETH'}
              decimals={18}
              sigFigs={6}
            />
          ),
        }}
        values={{
          symbol: native?.symbol ?? 'ETH',
        }}
      />
    )
  } else {
    return (
      <Trans
        i18nKey="account.transactionSummary.wrapTo"
        components={{
          amount: (
            <FormattedCurrencyAmount
              rawAmount={currencyAmountRaw}
              symbol={native?.symbol ?? 'ETH'}
              decimals={18}
              sigFigs={6}
            />
          ),
        }}
        values={{
          symbol: native?.wrapped?.symbol ?? 'WETH',
        }}
      />
    )
  }
}

function DepositLiquidityStakingSummary() {
  // not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts
  // todo: deprecate and delete the code paths that allow this, show user more information
  return <Trans i18nKey="account.transactionSummary.depositLiquidity" />
}

function WithdrawLiquidityStakingSummary() {
  return <Trans i18nKey="account.transactionSummary.withdrawLiquidity" />
}

function MigrateLiquidityToV3Summary({
  info: { baseCurrencyId, quoteCurrencyId },
}: {
  info: MigrateV2LiquidityToV3TransactionInfo
}) {
  const baseCurrency = useCurrency(baseCurrencyId)
  const quoteCurrency = useCurrency(quoteCurrencyId)

  return (
    <Trans
      i18nKey="account.transactionSummary.migrateLiquidity"
      values={{
        baseSymbol: baseCurrency?.symbol,
        quoteSymbol: quoteCurrency?.symbol,
      }}
    />
  )
}

function CreateV3PoolSummary({ info: { quoteCurrencyId, baseCurrencyId } }: { info: CreateV3PoolTransactionInfo }) {
  const baseCurrency = useCurrency(baseCurrencyId)
  const quoteCurrency = useCurrency(quoteCurrencyId)

  return (
    <Trans
      i18nKey="account.transactionSummary.createPool"
      values={{
        baseSymbol: baseCurrency?.symbol,
        quoteSymbol: quoteCurrency?.symbol,
      }}
    />
  )
}

function CollectFeesSummary({ info: { currencyId0, currencyId1 } }: { info: CollectFeesTransactionInfo }) {
  const currency0 = useCurrency(currencyId0)
  const currency1 = useCurrency(currencyId1)

  return (
    <Trans
      i18nKey="account.transactionSummary.collectFees"
      values={{
        symbol0: currency0?.symbol,
        symbol1: currency1?.symbol,
      }}
    />
  )
}

function RemoveLiquidityV3Summary({
  info: { baseCurrencyId, quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw },
}: {
  info: RemoveLiquidityV3TransactionInfo
}) {
  return (
    <Trans
      i18nKey="account.transactionSummary.removeLiquiditySummary"
      components={{
        base: (
          <FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} />
        ),
        quote: (
          <FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />
        ),
      }}
    />
  )
}

function AddLiquidityV3PoolSummary({
  info: { createPool, quoteCurrencyId, baseCurrencyId },
}: {
  info: AddLiquidityV3PoolTransactionInfo
}) {
  const baseCurrency = useCurrency(baseCurrencyId)
  const quoteCurrency = useCurrency(quoteCurrencyId)

  return createPool ? (
    <Trans
      i18nKey="account.transactionSummary.createAddLiquidity"
      values={{
        baseSymbol: baseCurrency?.symbol,
        quoteSymbol: quoteCurrency?.symbol,
      }}
    />
  ) : (
    <Trans
      i18nKey="account.transactionSummary.addLiquidity"
      values={{
        baseSymbol: baseCurrency?.symbol,
        quoteSymbol: quoteCurrency?.symbol,
      }}
    />
  )
}

function AddLiquidityV2PoolSummary({
  info: { quoteCurrencyId, expectedAmountBaseRaw, expectedAmountQuoteRaw, baseCurrencyId },
}: {
  info: AddLiquidityV2PoolTransactionInfo
}) {
  return (
    <Trans
      i18nKey="account.transactionSummary.addLiquidityv2"
      components={{
        base: (
          <FormattedCurrencyAmountManaged rawAmount={expectedAmountBaseRaw} currencyId={baseCurrencyId} sigFigs={3} />
        ),
        quote: (
          <FormattedCurrencyAmountManaged rawAmount={expectedAmountQuoteRaw} currencyId={quoteCurrencyId} sigFigs={3} />
        ),
      }}
    />
  )
}

function SendSummary({ info }: { info: SendTransactionInfo }) {
  return (
    <Trans
      i18nKey="account.transactionSummary.sendSummary"
      components={{
        amount: <FormattedCurrencyAmountManaged rawAmount={info.amount} currencyId={info.currencyId} sigFigs={6} />,
      }}
      values={{
        recipient: info.recipient,
      }}
    />
  )
}

function SwapSummary({ info }: { info: ExactInputSwapTransactionInfo | ExactOutputSwapTransactionInfo }) {
  if (info.tradeType === TradeType.EXACT_INPUT) {
    return (
      <Trans
        i18nKey="account.transactionSummary.swapExactIn"
        components={{
          amount1: (
            <FormattedCurrencyAmountManaged
              rawAmount={info.inputCurrencyAmountRaw}
              currencyId={info.inputCurrencyId}
              sigFigs={6}
            />
          ),
          amount2: (
            <FormattedCurrencyAmountManaged
              rawAmount={info.settledOutputCurrencyAmountRaw ?? info.expectedOutputCurrencyAmountRaw}
              currencyId={info.outputCurrencyId}
              sigFigs={6}
            />
          ),
        }}
      />
    )
  } else {
    return (
      <Trans
        i18nKey="account.transactionSummary.swapExactOut"
        components={{
          amount1: (
            <FormattedCurrencyAmountManaged
              rawAmount={info.expectedInputCurrencyAmountRaw}
              currencyId={info.inputCurrencyId}
              sigFigs={6}
            />
          ),
          amount2: (
            <FormattedCurrencyAmountManaged
              rawAmount={info.outputCurrencyAmountRaw}
              currencyId={info.outputCurrencyId}
              sigFigs={6}
            />
          ),
        }}
      />
    )
  }
}
export function TransactionSummary({ info }: { info: TransactionInfo }) {
  switch (info.type) {
    case TransactionType.ADD_LIQUIDITY_V3_POOL:
      return <AddLiquidityV3PoolSummary info={info} />

    case TransactionType.ADD_LIQUIDITY_V2_POOL:
      return <AddLiquidityV2PoolSummary info={info} />

    case TransactionType.CLAIM:
      return <ClaimSummary info={info} />

    case TransactionType.DEPOSIT_LIQUIDITY_STAKING:
      return <DepositLiquidityStakingSummary />

    case TransactionType.WITHDRAW_LIQUIDITY_STAKING:
      return <WithdrawLiquidityStakingSummary />

    case TransactionType.SWAP:
      return <SwapSummary info={info} />

    case TransactionType.APPROVAL:
      return <ApprovalSummary info={info} />

    case TransactionType.VOTE:
      return <VoteSummary info={info} />

    case TransactionType.DELEGATE:
      return <DelegateSummary info={info} />

    case TransactionType.WRAP:
      return <WrapSummary info={info} />

    case TransactionType.CREATE_V3_POOL:
      return <CreateV3PoolSummary info={info} />

    case TransactionType.MIGRATE_LIQUIDITY_V3:
      return <MigrateLiquidityToV3Summary info={info} />

    case TransactionType.COLLECT_FEES:
      return <CollectFeesSummary info={info} />

    case TransactionType.REMOVE_LIQUIDITY_V3:
      return <RemoveLiquidityV3Summary info={info} />

    case TransactionType.QUEUE:
      return <QueueSummary info={info} />

    case TransactionType.EXECUTE:
      return <ExecuteSummary info={info} />

    case TransactionType.SUBMIT_PROPOSAL:
      return <SubmitProposalTransactionSummary />

    case TransactionType.SEND:
      return <SendSummary info={info} />
  }
}
