// eslint-disable-next-line no-restricted-imports
import { ProtocolVersion } from '@uniswap/client-pools/dist/pools/v1/types_pb'
import {
  LiquidityPositionRangeChart,
  LiquidityPositionRangeChartLoader,
} from 'components/Charts/LiquidityPositionRangeChart/LiquidityPositionRangeChart'
import {
  LiquidityPositionFeeStats,
  LiquidityPositionFeeStatsLoader,
} from 'components/Liquidity/LiquidityPositionFeeStats'
import { LiquidityPositionInfo, LiquidityPositionInfoLoader } from 'components/Liquidity/LiquidityPositionInfo'
import { useGetRangeDisplay, useV3OrV4PositionDerivedInfo } from 'components/Liquidity/hooks'
import { PositionInfo } from 'components/Liquidity/types'
import { PriceOrdering } from 'components/PositionListItem'
import { MouseoverTooltip } from 'components/Tooltip'
import { MenuContent } from 'components/menus/ContextMenuContent'
import { ContextMenu, MenuOptionItem } from 'components/menus/ContextMenuV2'
import { getPoolDetailsURL } from 'graphql/data/util'
import { useSwitchChain } from 'hooks/useSwitchChain'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { setOpenModal } from 'state/application/reducer'
import { useAppDispatch } from 'state/hooks'
import { ClickableTamaguiStyle } from 'theme/components'
import { Flex, Popover, Shine, Text, TouchableArea, useIsTouchDevice, useSporeColors } from 'ui/src'
import { ArrowsLeftRight } from 'ui/src/components/icons/ArrowsLeftRight'
import { Dollar } from 'ui/src/components/icons/Dollar'
import { Eye } from 'ui/src/components/icons/Eye'
import { EyeOff } from 'ui/src/components/icons/EyeOff'
import { InfoCircleFilled } from 'ui/src/components/icons/InfoCircleFilled'
import { Minus } from 'ui/src/components/icons/Minus'
import { MoreHorizontal } from 'ui/src/components/icons/MoreHorizontal'
import { Plus } from 'ui/src/components/icons/Plus'
import { RightArrow } from 'ui/src/components/icons/RightArrow'
import { iconSizes } from 'ui/src/theme'
import { getChainInfo } from 'uniswap/src/features/chains/chainInfo'
import { toGraphQLChain } from 'uniswap/src/features/chains/utils'
import { FeatureFlags } from 'uniswap/src/features/gating/flags'
import { useFeatureFlag } from 'uniswap/src/features/gating/hooks'
import { useLocalizationContext } from 'uniswap/src/features/language/LocalizationContext'
import { ModalName } from 'uniswap/src/features/telemetry/constants'
import { useUSDCValue } from 'uniswap/src/features/transactions/swap/hooks/useUSDCPrice'
import { togglePositionVisibility } from 'uniswap/src/features/visibility/slice'
import { NumberType } from 'utilities/src/format/types'
import { isV4UnsupportedChain } from 'utils/networkSupportsV4'
import { useAccount } from 'wagmi'

export function LiquidityPositionCardLoader() {
  return (
    <Shine>
      <Flex
        p="$spacing24"
        gap="$spacing24"
        borderWidth="$spacing1"
        borderRadius="$rounded20"
        borderColor="$surface3"
        width="100%"
        overflow="hidden"
        $md={{ gap: '$gap20' }}
      >
        <Flex
          row
          alignItems="center"
          justifyContent="space-between"
          $md={{ row: false, alignItems: 'flex-start', gap: '$gap20' }}
        >
          <LiquidityPositionInfoLoader />
          <LiquidityPositionRangeChartLoader />
        </Flex>
        <LiquidityPositionFeeStatsLoader />
      </Flex>
    </Shine>
  )
}

export function LiquidityPositionCard({
  liquidityPosition,
  isMiniVersion,
  isClickableStyle,
  showVisibilityOption,
  isVisible = true,
}: {
  liquidityPosition: PositionInfo
  isMiniVersion?: boolean
  isClickableStyle?: boolean
  showVisibilityOption?: boolean
  isVisible?: boolean
}) {
  const { formatCurrencyAmount } = useLocalizationContext()
  const { t } = useTranslation()
  const isTouchDevice = useIsTouchDevice()
  const isV4Enabled = useFeatureFlag(FeatureFlags.V4Data)
  const isMigrateEnabled = useFeatureFlag(FeatureFlags.MigrateV3ToV4)
  const [pricesInverted, setPricesInverted] = useState(false)

  const dispatch = useAppDispatch()
  const navigate = useNavigate()
  const account = useAccount()
  const switchChain = useSwitchChain()
  const { fiatFeeValue0, fiatFeeValue1, fiatValue0, fiatValue1, priceOrdering, apr } =
    useV3OrV4PositionDerivedInfo(liquidityPosition)

  const token0USDValue = useUSDCValue(liquidityPosition.currency0Amount)
  const token1USDValue = useUSDCValue(liquidityPosition.currency1Amount)

  const v3OrV4FormattedUsdValue =
    fiatValue0 && fiatValue1
      ? formatCurrencyAmount({
          value: fiatValue0.add(fiatValue1),
          type: NumberType.FiatStandard,
        })
      : undefined
  const v2FormattedUsdValue =
    token0USDValue && token1USDValue
      ? formatCurrencyAmount({ value: token0USDValue.add(token1USDValue), type: NumberType.FiatStandard })
      : undefined

  const v3OrV4FormattedFeesValue =
    fiatFeeValue0 && fiatFeeValue1
      ? formatCurrencyAmount({
          value: fiatFeeValue0.add(fiatFeeValue1),
          type: NumberType.FiatStandard,
        })
      : undefined

  const dropdownOptions = useMemo(() => {
    const hideOption = [
      {
        key: 'position-card-hide-liquidity',
        onPress: () => {
          dispatch(
            togglePositionVisibility({
              poolId: liquidityPosition.poolId,
              tokenId: liquidityPosition.tokenId,
              chainId: liquidityPosition.chainId,
            }),
          )
        },
        label: isVisible ? t('common.hide.button') : t('common.unhide'),
        Icon: isVisible ? EyeOff : Eye,
        showDivider: true,
      },
    ]

    const v2Options = [
      {
        key: 'position-card-add-liquidity',
        onPress: () => {
          dispatch(setOpenModal({ name: ModalName.AddLiquidity, initialState: liquidityPosition }))
        },
        label: t('common.addLiquidity'),
        Icon: Plus,
      },
      {
        key: 'position-card-remove-liquidity',
        onPress: () => {
          dispatch(setOpenModal({ name: ModalName.RemoveLiquidity, initialState: liquidityPosition }))
        },
        label: t('pool.removeLiquidity'),
        Icon: Minus,
      },
    ]

    const chainInfo = getChainInfo(liquidityPosition.chainId)

    const migrateV2Option = {
      key: 'position-card-migrate',
      onPress: async () => {
        if (chainInfo.id !== account.chainId) {
          await switchChain(chainInfo.id)
        }
        navigate(`/migrate/v2/${liquidityPosition.liquidityToken?.address ?? ''}`)
      },
      label: t('pool.migrateLiquidity'),
      Icon: RightArrow,
    }

    if (liquidityPosition.version === ProtocolVersion.V2) {
      return [...v2Options, migrateV2Option, ...(showVisibilityOption ? hideOption : [])]
    }

    const migrateV3Option = isV4UnsupportedChain(liquidityPosition.chainId)
      ? undefined
      : {
          key: 'position-card-migrate',
          onPress: () => {
            navigate(`/migrate/v3/${chainInfo.urlParam}/${liquidityPosition.tokenId}`)
          },
          label: t('pool.migrateLiquidity'),
          Icon: RightArrow,
        }

    return [
      {
        key: 'position-card-collect-fees',
        onPress: () => {
          dispatch(
            setOpenModal({ name: ModalName.ClaimFee, initialState: { ...liquidityPosition, collectAsWeth: false } }),
          )
        },
        label: t('pool.collectFees'),
        Icon: Dollar,
      },
      ...v2Options,
      ...(isV4Enabled && isMigrateEnabled && migrateV3Option ? [migrateV3Option] : []),
      {
        key: 'position-card-pool-info',
        onPress: () => {
          if (!liquidityPosition.poolId) {
            return
          }

          navigate(getPoolDetailsURL(liquidityPosition.poolId, toGraphQLChain(liquidityPosition.chainId)))
        },
        label: t('pool.info'),
        Icon: InfoCircleFilled,
      },
      ...(showVisibilityOption ? hideOption : []),
    ]
  }, [
    showVisibilityOption,
    liquidityPosition,
    isMigrateEnabled,
    isV4Enabled,
    dispatch,
    isVisible,
    t,
    account.chainId,
    navigate,
    switchChain,
  ])

  const priceOrderingForChart = useMemo(() => {
    if (
      (liquidityPosition?.version !== ProtocolVersion.V3 && liquidityPosition?.version !== ProtocolVersion.V4) ||
      !liquidityPosition.position ||
      !liquidityPosition.liquidity ||
      !liquidityPosition.tickLower ||
      !liquidityPosition.tickUpper
    ) {
      return {}
    }
    return {
      base: pricesInverted ? liquidityPosition.position.amount1.currency : liquidityPosition.position.amount0.currency,
      priceLower: liquidityPosition.position.token0PriceLower,
      priceUpper: liquidityPosition.position.token0PriceUpper,
    }
  }, [liquidityPosition, pricesInverted])

  return (
    <ContextMenu menuItems={dropdownOptions} alignContentLeft={isMiniVersion}>
      {isMiniVersion ? (
        <MiniPositionCard
          menuOptions={dropdownOptions}
          isClickableStyle={isClickableStyle}
          positionInfo={liquidityPosition}
          formattedUsdValue={v3OrV4FormattedUsdValue ?? v2FormattedUsdValue}
          formattedUsdFees={v3OrV4FormattedFeesValue}
          priceOrdering={priceOrdering}
          tickSpacing={liquidityPosition.tickSpacing}
          tickLower={liquidityPosition.tickLower}
          tickUpper={liquidityPosition.tickUpper}
        />
      ) : (
        <Flex
          group
          position="relative"
          p="$spacing24"
          gap="$spacing24"
          borderWidth="$spacing1"
          borderRadius="$rounded20"
          borderColor="$surface3"
          width="100%"
          overflow="hidden"
          $md={{ gap: '$gap20' }}
          hoverStyle={isClickableStyle ? { backgroundColor: '$surface1Hovered', borderColor: '$surface3Hovered' } : {}}
          pressStyle={isClickableStyle ? { backgroundColor: '$surface1Pressed', borderColor: '$surface3Pressed' } : {}}
        >
          <Flex
            row
            alignItems="center"
            justifyContent="space-between"
            $md={{ row: false, alignItems: 'flex-start', gap: '$gap20' }}
          >
            <LiquidityPositionInfo positionInfo={liquidityPosition} />
            <LiquidityPositionRangeChart
              version={liquidityPosition.version}
              chainId={liquidityPosition.chainId}
              currency0={
                pricesInverted ? liquidityPosition.currency1Amount.currency : liquidityPosition.currency0Amount.currency
              }
              currency1={
                pricesInverted ? liquidityPosition.currency0Amount.currency : liquidityPosition.currency1Amount.currency
              }
              positionStatus={liquidityPosition.status}
              poolAddressOrId={liquidityPosition.poolId}
              priceOrdering={priceOrderingForChart}
            />
          </Flex>
          <LiquidityPositionFeeStats
            formattedUsdValue={v3OrV4FormattedUsdValue ?? v2FormattedUsdValue}
            formattedUsdFees={v3OrV4FormattedFeesValue}
            priceOrdering={priceOrdering}
            tickSpacing={liquidityPosition.tickSpacing}
            tickLower={liquidityPosition.tickLower}
            tickUpper={liquidityPosition.tickUpper}
            version={liquidityPosition.version}
            apr={apr}
            pricesInverted={pricesInverted}
            setPricesInverted={setPricesInverted}
          />
          {!isTouchDevice && <PositionPopoverMoreMenu menuOptions={dropdownOptions} />}
        </Flex>
      )}
    </ContextMenu>
  )
}

function MiniPositionCard({
  positionInfo,
  menuOptions,
  formattedUsdFees,
  formattedUsdValue,
  priceOrdering,
  tickSpacing,
  tickLower,
  tickUpper,
  isClickableStyle,
}: {
  positionInfo: PositionInfo
  menuOptions: MenuOptionItem[]
  formattedUsdFees?: string
  formattedUsdValue?: string
  priceOrdering: PriceOrdering
  tickSpacing?: number
  tickLower?: string
  tickUpper?: string
  isClickableStyle?: boolean
}) {
  const { t } = useTranslation()
  const [pricesInverted, setPricesInverted] = useState(false)

  const { maxPrice, minPrice, tokenASymbol, tokenBSymbol, isFullRange } = useGetRangeDisplay({
    priceOrdering,
    tickSpacing,
    tickLower,
    tickUpper,
    pricesInverted,
  })

  return (
    <Flex
      gap="$gap20"
      p="$padding16"
      borderRadius="$rounded20"
      borderColor="$surface3"
      borderWidth="$spacing1"
      position="relative"
      m="$spacing16"
      group
      hoverStyle={isClickableStyle ? { backgroundColor: '$surface1Hovered', borderColor: '$surface3Hovered' } : {}}
      pressStyle={isClickableStyle ? { backgroundColor: '$surface1Pressed', borderColor: '$surface3Pressed' } : {}}
    >
      <LiquidityPositionInfo hideStatusIndicator positionInfo={positionInfo} currencyLogoSize={32} />
      <Flex row gap="$gap12">
        <Flex>
          {formattedUsdValue ? (
            <Text variant="body2">{formattedUsdValue}</Text>
          ) : (
            <MouseoverTooltip text={t('position.valueUnavailable')} placement="top">
              <Text variant="body2">-</Text>
            </MouseoverTooltip>
          )}
          <Text variant="body4" color="$neutral2">
            {t('pool.position')}
          </Text>
        </Flex>
        <Flex>
          <Text variant="body2">{formattedUsdFees || t('common.unavailable')}</Text>
          <Text variant="body4" color="$neutral2">
            {t('common.fees')}
          </Text>
        </Flex>
      </Flex>
      {priceOrdering.priceLower && priceOrdering.priceUpper && !isFullRange ? (
        <TouchableArea
          {...ClickableTamaguiStyle}
          onPress={(e) => {
            e.preventDefault()
            e.stopPropagation()
            setPricesInverted((prevInverted) => !prevInverted)
          }}
        >
          <Flex row gap={10}>
            <Text variant="body4">
              {minPrice} {tokenASymbol} / {tokenBSymbol}
            </Text>
            <ArrowsLeftRight color="$neutral2" size="$icon.16" />
            <Text variant="body4">
              {maxPrice} {tokenASymbol} / {tokenBSymbol}
            </Text>
          </Flex>
        </TouchableArea>
      ) : (
        <Text variant="body4">{t('common.fullRange')}</Text>
      )}
      <PositionPopoverMoreMenu menuOptions={menuOptions} />
    </Flex>
  )
}

const PositionPopoverMoreMenu = ({ menuOptions }: { menuOptions: MenuOptionItem[] }) => {
  const colors = useSporeColors()

  return (
    <Popover placement="bottom-end" allowFlip offset={{ crossAxis: 6 }}>
      <TouchableArea
        position="absolute"
        top="$spacing16"
        right="$spacing16"
        animation="fast"
        opacity={0}
        borderRadius="$rounded12"
        $group-hover={{ opacity: 1, pointerEvents: 'auto', backgroundColor: '$surface3Hovered' }}
        onPress={(event) => {
          event.preventDefault()
          event.stopPropagation()
        }}
      >
        <Popover.Trigger p="$spacing8">
          <MoreHorizontal size={iconSizes.icon16} color={colors.neutral1.val} />
        </Popover.Trigger>
      </TouchableArea>
      <Popover.Content
        animation="125ms"
        enterStyle={{
          opacity: 0,
          scale: 0.98,
          transform: [{ translateY: -4 }],
        }}
        backgroundColor="transparent"
      >
        <MenuContent items={menuOptions} />
      </Popover.Content>
    </Popover>
  )
}
