import useMangoStore, { PerpPosition } from '../stores/useMangoStore'
import BN from 'bn.js'
import {
  MangoAccount,
  MangoCache,
  MangoGroup,
  nativeI80F48ToUi,
  PerpMarket,
  PerpMarketConfig,
} from '@blockworks-foundation/mango-client'
import {
  mangoCacheSelector,
  mangoGroupConfigSelector,
  mangoGroupSelector,
  marketsSelector,
} from '../stores/selectors'
import { useEffect } from 'react'
import useMangoAccount from './useMangoAccount'

export const collectPerpPosition = (
  mangoAccount: MangoAccount,
  mangoGroup: MangoGroup,
  mangoCache: MangoCache,
  marketConfig: PerpMarketConfig,
  perpMarket: PerpMarket,
  tradeHistory: any
): PerpPosition | undefined => {
  if (
    !mangoAccount ||
    !mangoGroup ||
    !mangoCache ||
    !perpMarket ||
    !tradeHistory
  )
    return

  const perpMarketInfo = mangoGroup.perpMarkets[marketConfig.marketIndex]
  const perpAccount = mangoAccount.perpAccounts[marketConfig.marketIndex]

  let avgEntryPrice = 0,
    breakEvenPrice = 0
  const perpTradeHistory = tradeHistory.filter(
    (t) => t.marketName === marketConfig.name
  )
  try {
    avgEntryPrice = perpAccount
      .getAverageOpenPrice(mangoAccount, perpMarket, perpTradeHistory)
      .toNumber()
  } catch (e) {
    console.error(marketConfig.name, e)
  }

  try {
    breakEvenPrice = perpAccount
      .getBreakEvenPrice(mangoAccount, perpMarket, perpTradeHistory)
      .toNumber()
  } catch (e) {
    console.error(marketConfig.name, e)
  }

  const basePosition = perpMarket?.baseLotsToNumber(perpAccount.basePosition)
  const indexPrice = mangoGroup
    .getPrice(marketConfig.marketIndex, mangoCache)
    .toNumber()
  const notionalSize = Math.abs(basePosition * indexPrice)
  const unrealizedPnl = basePosition * (indexPrice - breakEvenPrice)
  const unsettledPnl = +nativeI80F48ToUi(
    perpAccount.getPnl(
      perpMarketInfo,
      mangoCache.perpMarketCache[marketConfig.marketIndex],
      mangoCache.priceCache[marketConfig.marketIndex].price
    ),
    marketConfig.quoteDecimals
  ).toNumber()

  return {
    perpMarketInfo,
    marketConfig,
    perpMarket,
    perpAccount,
    basePosition,
    indexPrice,
    avgEntryPrice,
    breakEvenPrice,
    notionalSize,
    unrealizedPnl,
    unsettledPnl,
  }
}

const usePerpPositions = () => {
  const setMangoStore = useMangoStore((s) => s.set)
  const { mangoAccount } = useMangoAccount()
  const groupConfig = useMangoStore(mangoGroupConfigSelector)
  const mangoGroup = useMangoStore(mangoGroupSelector)
  const mangoCache = useMangoStore(mangoCacheSelector)
  const allMarkets = useMangoStore(marketsSelector)
  const tradeHistory = useMangoStore((s) => s.tradeHistory.parsed)

  useEffect(() => {
    if (
      mangoAccount &&
      mangoGroup &&
      mangoCache &&
      Object.keys(allMarkets).length
    ) {
      const perpPositions = mangoAccount
        ? groupConfig.perpMarkets.map((m) =>
            collectPerpPosition(
              mangoAccount,
              mangoGroup,
              mangoCache,
              m,
              allMarkets[m.publicKey.toBase58()] as PerpMarket,
              tradeHistory
            )
          )
        : []

      const openPerpPositions = perpPositions.filter(
        (p) =>
          p?.perpAccount?.basePosition &&
          !p.perpAccount.basePosition.eq(new BN(0))
      ) as PerpPosition[]

      setMangoStore((state) => {
        state.selectedMangoAccount.perpPositions = perpPositions
        state.selectedMangoAccount.openPerpPositions = openPerpPositions
        if (
          openPerpPositions.length !==
          state.selectedMangoAccount.totalOpenPerpPositions
        ) {
          state.selectedMangoAccount.totalOpenPerpPositions =
            openPerpPositions.length
        }
        state.selectedMangoAccount.unsettledPerpPositions =
          perpPositions.filter(
            (p) =>
              p?.perpAccount?.basePosition?.eq(new BN(0)) &&
              p?.unsettledPnl != 0
          ) as PerpPosition[]
      })
    }
  }, [mangoAccount, mangoCache, tradeHistory])
}

export default usePerpPositions
