import { useCallback, useMemo, useState } from 'react'
import { ElementTitle } from './styles'
import useMangoStore from '../stores/useMangoStore'
import { formatUsdValue, getPrecisionDigits, roundPerpSize } from '../utils'
import Button, { LinkButton } from './Button'
import Tooltip from './Tooltip'
import PerpSideBadge from './PerpSideBadge'
import {
  getMarketIndexBySymbol,
  MangoAccount,
  PerpAccount,
  PerpMarket,
  QUOTE_INDEX,
} from '@blockworks-foundation/mango-client'
import { notify } from '../utils/notifications'
import MarketCloseModal from './MarketCloseModal'
import PnlText from './PnlText'
import Loading from './Loading'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid'
import { useTranslation } from 'next-i18next'
import useMangoAccount from '../hooks/useMangoAccount'
import { useWallet, Wallet } from '@solana/wallet-adapter-react'
import { useRouter } from 'next/router'

export const settlePosPnl = async (
  perpMarkets: PerpMarket[],
  t,
  mangoAccounts: MangoAccount[] | undefined,
  wallet: Wallet
) => {
  const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
  const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
  const mangoCache = useMangoStore.getState().selectedMangoGroup.cache
  const actions = useMangoStore.getState().actions
  const mangoClient = useMangoStore.getState().connection.client

  const rootBankAccount = mangoGroup?.rootBankAccounts[QUOTE_INDEX]

  if (!mangoGroup || !mangoCache || !mangoAccount || !rootBankAccount) return

  try {
    const txids = await mangoClient.settlePosPnl(
      mangoGroup,
      mangoCache,
      mangoAccount,
      perpMarkets,
      rootBankAccount,
      wallet?.adapter,
      mangoAccounts
    )
    actions.reloadMangoAccount()
    // FIXME: Remove filter when settlePosPnl return type is undefined or string[]
    const filteredTxids = txids?.filter(
      (x) => typeof x === 'string'
    ) as string[]
    if (filteredTxids) {
      for (const txid of filteredTxids) {
        notify({
          title: t('pnl-success'),
          description: '',
          txid,
        })
      }
    } else {
      notify({
        title: t('pnl-error'),
        description: t('transaction-failed'),
        type: 'error',
      })
    }
  } catch (e) {
    console.log('Error settling PNL: ', `${e}`)
    notify({
      title: t('pnl-error'),
      description: e.message,
      txid: e.txid,
      type: 'error',
    })
  }
}

export async function settleAllPnl(
  perpMarkets: PerpMarket[],
  t,
  mangoAccounts: MangoAccount[] | undefined,
  wallet: Wallet
) {
  const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
  const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
  const mangoCache = useMangoStore.getState().selectedMangoGroup.cache
  const actions = useMangoStore.getState().actions
  const mangoClient = useMangoStore.getState().connection.client

  const rootBankAccount = mangoGroup?.rootBankAccounts[QUOTE_INDEX]

  if (!mangoGroup || !mangoCache || !mangoAccount || !rootBankAccount) return

  try {
    const txids = await mangoClient.settleAllPerpPnl(
      mangoGroup,
      mangoCache,
      mangoAccount,
      perpMarkets,
      rootBankAccount,
      wallet?.adapter,
      mangoAccounts
    )
    actions.reloadMangoAccount()
    const filteredTxids = txids?.filter((x) => x !== null) as string[]
    if (filteredTxids) {
      for (const txid of filteredTxids) {
        notify({
          title: t('pnl-success'),
          description: '',
          txid,
        })
      }
    } else {
      notify({
        title: t('pnl-error'),
        description: t('transaction-failed'),
        type: 'error',
      })
    }
  } catch (e) {
    console.log('Error settling PNL: ', `${e}`)
    notify({
      title: t('pnl-error'),
      description: e.message,
      txid: e.txid,
      type: 'error',
    })
  }
}

export const settlePnl = async (
  perpMarket: PerpMarket,
  perpAccount: PerpAccount,
  t,
  mangoAccounts: MangoAccount[] | undefined,
  wallet: Wallet
) => {
  const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
  const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
  const mangoCache = useMangoStore.getState().selectedMangoGroup.cache
  const actions = useMangoStore.getState().actions
  const marketIndex = mangoGroup?.getPerpMarketIndex(perpMarket.publicKey)
  const mangoClient = useMangoStore.getState().connection.client
  const rootBank = mangoGroup?.rootBankAccounts[QUOTE_INDEX]

  if (
    !rootBank ||
    !mangoGroup ||
    !mangoCache ||
    !mangoAccount ||
    typeof marketIndex !== 'number'
  )
    return

  try {
    const txid = await mangoClient.settlePnl(
      mangoGroup,
      mangoCache,
      mangoAccount,
      perpMarket,
      rootBank,
      mangoCache.priceCache[marketIndex].price,
      wallet?.adapter,
      mangoAccounts
    )
    actions.reloadMangoAccount()
    if (txid) {
      notify({
        title: t('pnl-success'),
        description: '',
        txid,
      })
    } else {
      notify({
        title: t('pnl-error'),
        description: t('transaction-failed'),
        type: 'error',
      })
    }
  } catch (e) {
    console.log('Error settling PNL: ', `${e}`, `${perpAccount}`)
    notify({
      title: t('pnl-error'),
      description: e.message,
      txid: e.txid,
      type: 'error',
    })
  }
}

export default function MarketPosition() {
  const { t } = useTranslation('common')
  const { wallet, connected } = useWallet()
  const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
  const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
  const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
  const { mangoAccount, initialLoad } = useMangoAccount()
  const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
  const marketConfig = useMangoStore((s) => s.selectedMarket.config)
  const setMangoStore = useMangoStore((s) => s.set)
  const price = useMangoStore((s) => s.tradeForm.price)
  const perpPositions = useMangoStore(
    (s) => s.selectedMangoAccount.perpPositions
  )
  const baseSymbol = marketConfig.baseSymbol
  const marketName = marketConfig.name
  const router = useRouter()
  const { pubkey } = router.query

  const [showMarketCloseModal, setShowMarketCloseModal] = useState(false)
  const [settling, setSettling] = useState(false)
  const { width } = useViewport()
  const isMobile = width ? width < breakpoints.sm : false

  const marketIndex = useMemo(() => {
    return getMarketIndexBySymbol(mangoGroupConfig, baseSymbol)
  }, [mangoGroupConfig, baseSymbol])

  let perpAccount
  if (marketName.includes('PERP') && mangoAccount) {
    perpAccount = mangoAccount.perpAccounts[marketIndex]
  }

  const handleSizeClick = (size) => {
    if (!mangoGroup || !mangoCache || !selectedMarket) return
    const sizePrecisionDigits = getPrecisionDigits(selectedMarket.minOrderSize)
    const priceOrDefault = price
      ? price
      : mangoGroup.getPriceUi(marketIndex, mangoCache)
    const roundedSize = parseFloat(Math.abs(size).toFixed(sizePrecisionDigits))
    const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2))
    setMangoStore((state) => {
      state.tradeForm.baseSize = roundedSize
      state.tradeForm.quoteSize = quoteSize
      state.tradeForm.side = size > 0 ? 'sell' : 'buy'
    })
  }

  const handleCloseWarning = useCallback(() => {
    setShowMarketCloseModal(false)
  }, [])

  const handleSettlePnl = (perpMarket, perpAccount) => {
    if (wallet) {
      setSettling(true)
      settlePnl(perpMarket, perpAccount, t, undefined, wallet).then(() => {
        setSettling(false)
      })
    }
  }

  if (!mangoGroup || !selectedMarket || !(selectedMarket instanceof PerpMarket))
    return null

  const {
    basePosition = 0,
    avgEntryPrice = 0,
    breakEvenPrice = 0,
    notionalSize = 0,
    unsettledPnl = 0,
  } = perpPositions.length
    ? perpPositions.find((p) =>
        p?.perpMarket.publicKey.equals(selectedMarket.publicKey)
      ) ?? {}
    : {}

  function SettlePnlTooltip() {
    return (
      <div>
        {t('pnl-help')}{' '}
        <a
          href="https://docs.mango.markets/mango/settle-pnl"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('learn-more')}
        </a>
      </div>
    )
  }

  return (
    <>
      <div
        className={!connected && !isMobile && !pubkey ? 'blur-sm filter' : ''}
        id="perp-positions-tip"
      >
        {!isMobile ? (
          <ElementTitle>
            {marketConfig.name} {t('position')}
          </ElementTitle>
        ) : null}
        <div className="flex items-center justify-between pb-2">
          <div className="font-normal leading-4 text-th-fgd-3">{t('side')}</div>
          {initialLoad ? (
            <DataLoader />
          ) : (
            <PerpSideBadge perpAccount={perpAccount}></PerpSideBadge>
          )}
        </div>
        <div className="flex justify-between pb-2">
          <div className="font-normal leading-4 text-th-fgd-3">
            {t('position-size')}
          </div>
          <div className="text-th-fgd-1">
            {initialLoad ? (
              <DataLoader />
            ) : basePosition ? (
              <span
                className="cursor-pointer underline hover:no-underline"
                onClick={() => handleSizeClick(basePosition)}
              >
                {`${roundPerpSize(basePosition, baseSymbol)} ${baseSymbol}`}
              </span>
            ) : (
              `0 ${baseSymbol}`
            )}
          </div>
        </div>
        <div className="flex justify-between pb-2">
          <div className="font-normal leading-4 text-th-fgd-3">
            {t('notional-size')}
          </div>
          <div className="text-th-fgd-1">
            {initialLoad ? (
              <DataLoader />
            ) : notionalSize ? (
              formatUsdValue(Math.abs(notionalSize))
            ) : (
              '$0'
            )}
          </div>
        </div>
        <div className="flex justify-between pb-2">
          <div className="font-normal leading-4 text-th-fgd-3">
            {t('average-entry')}
          </div>
          <div className="text-th-fgd-1">
            {initialLoad ? (
              <DataLoader />
            ) : avgEntryPrice ? (
              formatUsdValue(avgEntryPrice)
            ) : (
              '$0'
            )}
          </div>
        </div>
        <div className="flex justify-between pb-2">
          <div className="font-normal leading-4 text-th-fgd-3">
            {t('break-even')}
          </div>
          <div className="text-th-fgd-1">
            {initialLoad ? (
              <DataLoader />
            ) : breakEvenPrice ? (
              formatUsdValue(breakEvenPrice)
            ) : (
              '$0'
            )}
          </div>
        </div>
        <div className="flex justify-between pb-2">
          <Tooltip content={<SettlePnlTooltip />}>
            <Tooltip.Content className="font-normal leading-4 text-th-fgd-3">
              {t('unsettled-balance')}
            </Tooltip.Content>
          </Tooltip>
          <div className="flex items-center">
            {initialLoad ? <DataLoader /> : <PnlText pnl={unsettledPnl} />}
            {settling ? (
              <Loading className="ml-2" />
            ) : (
              <LinkButton
                onClick={() => handleSettlePnl(selectedMarket, perpAccount)}
                className="ml-2 text-xs text-th-primary disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:underline"
                disabled={unsettledPnl === 0}
              >
                {t('redeem-pnl')}
              </LinkButton>
            )}
          </div>
        </div>
        {basePosition ? (
          <Button
            onClick={() => setShowMarketCloseModal(true)}
            className="mt-2.5 w-full"
            primary={false}
          >
            <span>{t('market-close')}</span>
          </Button>
        ) : null}
      </div>
      {showMarketCloseModal ? (
        <MarketCloseModal
          isOpen={showMarketCloseModal}
          onClose={handleCloseWarning}
          position={{ marketConfig: marketConfig, perpMarket: selectedMarket }}
        />
      ) : null}
    </>
  )
}

export const DataLoader = () => (
  <div className="h-5 w-10 animate-pulse rounded-sm bg-th-bkg-3" />
)
