import { useEffect, useMemo } from "react"
import { useAccount } from "wagmi"

import { SupportedChainIds } from "@/types"

import useStore from "../store"
import { MorphoTokensOptions } from "../types"
import usePolling from "@/hooks/usePolling"
import { MORPHO_STRATEGY_TOKENS } from "@/components/shared/constants"
import { MORPHO_YIELD_AUTOMATION_ACTIVE_STATE } from "../constants"
import { baseWagmiConfig as wagmiConfig } from "@/wagmi"
import { readContract } from "@wagmi/core"
import { formatUnits, sliceDecimalString } from "@/utils"
import { fetchAutomationsFromEoa } from "@/components/shared/api"
import { dispatchToast } from "@/components/shared/components"

const abi = [
  {
    inputs: [
      { internalType: "address", name: "start", type: "address" },
      { internalType: "uint256", name: "pageSize", type: "uint256" },
    ],
    name: "getModulesPaginated",
    outputs: [
      { internalType: "address[]", name: "array", type: "address[]" },
      { internalType: "address", name: "next", type: "address" },
    ],
    stateMutability: "view",
    type: "function",
  },
] as const

export default function useMorphoPositions(token: MorphoTokensOptions) {
  const {
    fetchMorphoUserPositions,
    userPositions,
    resetUserPostion,
    automationConsoleAddress,
    setAutomationConsoleAddress,
    loopFetchingPositions,
    resetAutomationConsoleAddress,
    morphoVaults,
    setPageSpinnerState,
  } = useStore()
  const { address: eoaAddress, chainId } = useAccount()
  const isUserPositionLoading = userPositions[token]?.loading

  const tokenConfig = MORPHO_STRATEGY_TOKENS[token]

  const userPositionData = useMemo(() => {
    return tokenConfig
      ? (userPositions[token]?.data || []).filter(
          (pos) =>
            (pos?.metadata?.baseToken || "").toLowerCase() ===
              tokenConfig.address.toLowerCase() &&
            pos?.metadata?.type === "EARN",
        )
      : []
  }, [token, tokenConfig, userPositions])

  const userPositionVault = useMemo(() => {
    const userMorphoPositionsVaultAddress =
      userPositionData.length > 0
        ? userPositionData[0].vaultPositionData?.vault.address
        : null

    const userPositionVault = userMorphoPositionsVaultAddress
      ? morphoVaults.vaults.find(
          (vault) =>
            (vault.address || "").toLowerCase() ===
            userMorphoPositionsVaultAddress.toLowerCase(),
        )
      : null

    if (!userPositionVault) return null

    return {
      name: userPositionVault.name,
      apy: `${userPositionVault.state.netApy.toFixed(2)} %`,
      liquidity: sliceDecimalString(
        formatUnits(userPositionVault.liquidity.underlying, 18),
        2,
        true,
      ),
      supply: `$ ${sliceDecimalString(
        userPositionVault.supply.usd.toString(),
        2,
        true,
      )}`,
    }
  }, [morphoVaults.vaults, userPositionData])

  useEffect(() => {
    const fetchUserAddress = async () => {
      try {
        if (
          !eoaAddress ||
          !tokenConfig ||
          !automationConsoleAddress[token].loading ||
          loopFetchingPositions
        )
          return

        setPageSpinnerState(true)
        const automationsFromEoa = await fetchAutomationsFromEoa(eoaAddress)

        console.log("fetchUserAddress : automationsFromEoa", automationsFromEoa)

        const filteredAutomations = automationsFromEoa.filter((automation) => {
          const areTokenSame =
            (automation.metadata.baseToken || "").toLowerCase() ===
            tokenConfig.address.toLowerCase()

          return (
            areTokenSame &&
            automation.status === MORPHO_YIELD_AUTOMATION_ACTIVE_STATE &&
            automation?.metadata?.type === "EARN"
          )
        })

        console.log(
          "fetchUserAddress : filteredAutomations",
          filteredAutomations,
        )

        // console.log("filteredAutomations", filteredAutomations);
        if (filteredAutomations.length > 0) {
          const subaccountAddress = filteredAutomations[0].subAccountAddress
          console.log(
            "subacc address for running automation ",
            subaccountAddress,
          )

          const readResponse = await readContract(wagmiConfig, {
            address: subaccountAddress,
            abi,
            functionName: "getModulesPaginated",
            args: ["0x0000000000000000000000000000000000000001", BigInt(2)],
          })

          console.log("User console address ", readResponse)
          const consoleAddress =
            readResponse.length > 0 &&
            readResponse[0].length > 1 &&
            readResponse[0][1]

          if (consoleAddress) {
            console.log("User console address: ", consoleAddress)
            setAutomationConsoleAddress(consoleAddress, token)
            await fetchMorphoUserPositions(
              consoleAddress,
              chainId as SupportedChainIds,
              token,
            )
            setPageSpinnerState(false)

            return
          }
        }

        // subacc address not found i.e. no automations found
        // reset user position
        resetUserPostion(token)
        setAutomationConsoleAddress(null, token)
        setPageSpinnerState(false)
      } catch (err: any) {
        console.error(err)
        dispatchToast({
          id: "error",
          type: "error",
          title: "Error fetching brahma account address",
          description: err?.message,
        })
      }
    }

    fetchUserAddress()
  }, [
    automationConsoleAddress,
    eoaAddress,
    loopFetchingPositions,
    setAutomationConsoleAddress,
    token,
    tokenConfig,
    tokenConfig?.address,
    resetUserPostion,
    fetchMorphoUserPositions,
    chainId,
    setPageSpinnerState,
  ])

  usePolling(() => {
    // poll only if user has position in state
    const consoleAddress = eoaAddress && automationConsoleAddress[token].address

    if (
      !automationConsoleAddress[token]?.loading &&
      !consoleAddress &&
      !loopFetchingPositions
    ) {
      resetUserPostion(token)
      return
    }

    if (!token || !chainId || !consoleAddress || userPositionData.length === 0)
      return

    const getMorphoPositions = async () => {
      await fetchMorphoUserPositions(
        consoleAddress,
        chainId as SupportedChainIds,
        token,
        true,
      )
    }
    getMorphoPositions()
  }, 30000)

  // reset user automation console address on EOA change

  useEffect(() => {
    if (!eoaAddress) return
    resetUserPostion(token)
    resetAutomationConsoleAddress(token)
  }, [eoaAddress, resetAutomationConsoleAddress, resetUserPostion, token])

  return {
    isUserPositionLoading,
    userPositionData,
    userPositionVault,
    consoleAddress: automationConsoleAddress[token]?.address,
  }
}
