// type useAutomationAgentProps = {}

import { useEffect, useMemo } from "react"
import { zeroAddress } from "viem"
import { useAccount } from "wagmi"
import { Address } from "brahma-console-kit"

import {
  BigAssetSelector,
  dispatchToast,
  FlexContainer,
  Typography,
} from "@/components/shared/components"
import BigAssetInputSelector from "@/components/shared/components/BigAssetInputSelector"
import usePolling from "@/hooks/usePolling"
import useAutomationAgentStore from "../../store"
import SelectTokenView from "../SelectTokenView"
import SelectAgentStep from "../steps/SelectAgentStep"
import ReviewStep from "../steps/ReviewStep"
import { formatAmountWithOptions } from "@/utils"
import AgentIsRunningStep from "../steps/AgentIsRunningStep"
import TradeDetailsStep from "../steps/TradeDetailsStep"
import ReviewStepButtonsSection from "../steps/ReviewStep/ReviewStepButtonsSection"
import { getTokenPrice } from "@/components/shared/api"
import { useIsMobile } from "@/hooks/use-is-mobile"
import { waitFor } from "@/components/morphoStrategy/utils"
import LoadingSelectAgentAnimationStep from "../steps/LoadingSelectAgentAnimationStep"
import useConfigStore from "@/components/shared/store"
import { useThemeContext } from "@/providers/themeProvider"
import { BASE_CHAIN_ID } from "@/constants"

type StepData = {
  component: JSX.Element
  isNextButtonDisabled?: boolean
  nextButtonCallback?: () => void | undefined
}

const MIN_USD_AMOUNT = 6

export default function useAutomationAgent() {
  const { address: eoaAddress } = useAccount()

  const {
    automations,
    currentStep,
    currentTab,
    selectedAgent,
    automationAgentData,
    eoaBalances: eoaAssets,
    balances: accountAssets,
    existingSafeAddress,
    preComputedConsoleAddress,
    fetchConsoleBalances,
    fetchPreComputedConsoleAddress,
    fetchExistingSwapAgentConsole,
    setSelectedAgent,
    goToNextStep,
    goToPreviousStep,
    updateAgentData,
    fetchEoaAssets,
    resetAgentsData,
    fetchAutomations,
    permissionModalData,
  } = useAutomationAgentStore()

  const { primaryToken, secondaryToken } = automationAgentData[selectedAgent]

  const isMobile = useIsMobile()

  const { theme } = useThemeContext()

  const { assets } = useConfigStore()

  const getMaxTokenBalanceAvailableForSurge: bigint =
    eoaAssets.data.find(
      (asset) =>
        asset.address.toLowerCase() ===
        (
          automationAgentData["SURGE"].secondaryToken?.address || ""
        ).toLowerCase(),
    )?.balanceOf?.value || BigInt(0)

  const getMaxTokenBalanceAvailableForPurge: bigint =
    eoaAssets.data.find(
      (asset) =>
        asset.address.toLowerCase() ===
        (
          automationAgentData["PURGE"].primaryToken?.address || ""
        ).toLowerCase(),
    )?.balanceOf?.value || BigInt(0)

  const stepData: StepData = useMemo(() => {
    if (currentStep === "SELECT_AGENT") {
      return {
        component: (
          <SelectAgentStep
            onSelectAgent={(agent) => {
              setSelectedAgent(agent)
              goToNextStep()
            }}
          />
        ),
        isNextButtonDisabled: true,
      }
    }

    if (currentStep === "LOADING_SELECT_AGENT_ANIMATION") {
      return {
        component: <LoadingSelectAgentAnimationStep />,
        isNextButtonDisabled: false,
      }
    }

    if (selectedAgent === "SURGE") {
      const {
        amount,
        duration,
        primaryToken,
        secondaryToken,
        slippage,
        tradeSizeAmount,
        selectedSlippage,
      } = automationAgentData["SURGE"]

      switch (currentStep) {
        case "ONE": {
          return {
            component: (
              <SelectTokenView
                title="Asset to Buy"
                subtitle="Select an asset that you’d like to dollar cost average"
              >
                <BigAssetSelector
                  size={isMobile ? "M" : "L"}
                  availableAssets={assets.filter(
                    (asset) => asset.address !== zeroAddress,
                  )}
                  selectedAsset={primaryToken}
                  setSelectedAsset={(asset) =>
                    updateAgentData("SURGE", { primaryToken: asset })
                  }
                  showBalance={false}
                  headerText="Select asset to buy"
                />
              </SelectTokenView>
            ),
            isNextButtonDisabled: !primaryToken,
          }
        }

        case "TWO": {
          const usdValueInputted =
            (secondaryToken?.prices?.default || 0) * parseFloat(amount || "0")
          const isValueInputtedAllowed = usdValueInputted > MIN_USD_AMOUNT

          const tokenAddress = secondaryToken?.address.toLowerCase() as Address
          const tokenBalance =
            accountAssets.data.find(
              (token) => token?.address.toLowerCase() === tokenAddress,
            )?.balanceOf?.formatted || "0.00"
          const usdValueTokenBalance =
            (secondaryToken?.prices?.default || 0) *
            parseFloat(tokenBalance || "0")

          const isConsoleBalanceAllowed = usdValueTokenBalance > MIN_USD_AMOUNT

          const isValueAllowed =
            isValueInputtedAllowed || isConsoleBalanceAllowed

          const handleNextButtonCallback = () => {
            if (
              !isValueAllowed ||
              isValueInputtedAllowed ||
              !isConsoleBalanceAllowed
            )
              return

            updateAgentData("SURGE", {
              amount: tokenBalance || "0",
            })
          }

          return {
            component: (
              <SelectTokenView
                title="Trading Budget (Allocate)"
                subtitle="Select an asset and amount from your balances"
              >
                <BigAssetInputSelector
                  warningText={
                    amount && !isValueAllowed
                      ? `Value should be more than $${MIN_USD_AMOUNT}`
                      : ""
                  }
                  showInputPresets
                  inputValue={amount}
                  setInputValue={(value) =>
                    updateAgentData("SURGE", {
                      amount: value,
                    })
                  }
                  selectedAsset={secondaryToken}
                  setSelectedAsset={async (asset) => {
                    if (
                      asset.address.toLowerCase() ===
                      primaryToken?.address.toLowerCase()
                    ) {
                      dispatchToast({
                        id: "same-token-error",
                        title: "Token Selection Error",
                        description: {
                          value:
                            "Primary and secondary tokens cannot be the same.",
                        },
                        type: "error",
                      })
                      console.log(
                        "Error: Primary and secondary tokens cannot be the same.",
                      )
                      return
                    }

                    updateAgentData("SURGE", {
                      secondaryToken: asset,
                      amount: asset.balanceOf?.formatted || "",
                    })
                    const price = await getTokenPrice(asset.address, "base")
                    updateAgentData("SURGE", {
                      secondaryToken: {
                        ...asset,
                        prices: { default: price.data || 0 },
                      },
                    })
                    await waitFor(200)
                  }}
                  getMaxTokenBalanceAvailable={
                    getMaxTokenBalanceAvailableForSurge
                  }
                  availableAssets={eoaAssets.data}
                />
                {isConsoleBalanceAllowed && secondaryToken && (
                  <Typography type="BODY_MEDIUM_S" color={theme.colors.success}>
                    {secondaryToken.name} Balance found: {tokenBalance} ($
                    {usdValueTokenBalance.toFixed(2)})
                  </Typography>
                )}
              </SelectTokenView>
            ),
            isNextButtonDisabled:
              !secondaryToken || !amount || !isValueAllowed || !eoaAddress,
            nextButtonCallback: handleNextButtonCallback,
          }
        }

        case "THREE": {
          return {
            component: (
              <TradeDetailsStep
                amount={amount}
                assetPrice={secondaryToken?.prices?.default || 0}
                logo={secondaryToken?.logo || ""}
                onMaxTradeAmountSet={(value) => {
                  updateAgentData("SURGE", { tradeSizeAmount: value })
                }}
                symbol={secondaryToken?.symbol || secondaryToken?.name || ""}
              />
            ),
            isNextButtonDisabled: !duration,
          }
        }

        case "FOUR": {
          return {
            component: (
              <FlexContainer
                justifyContent="space-between"
                height={100}
                style={{ minWidth: isMobile ? "100%" : "60rem" }}
                flexDirection="column"
                gap={4.8}
                opacityInEffect
              >
                <ReviewStep
                  duration={duration}
                  maxTradeSize={`${
                    amount
                      ? formatAmountWithOptions(tradeSizeAmount, {
                          maximumFractionDigits: 8,
                        })
                      : 0
                  } ${secondaryToken?.name}`}
                  primaryTitle="Buy"
                  secondaryTitle="Trading Budget"
                  primaryTokenDetail={`${primaryToken?.name}`}
                  secondaryTokenDetail={`${formatAmountWithOptions(amount, { maximumFractionDigits: 6 })} ${secondaryToken?.name}`}
                  primaryTokenLogo={primaryToken?.logo}
                  secondaryTokenLogo={secondaryToken?.logo}
                  slippage={slippage}
                  selectedSlippage={selectedSlippage}
                />
                <ReviewStepButtonsSection />
              </FlexContainer>
            ),
            isNextButtonDisabled: true,
          }
        }

        case "RUNNING": {
          return {
            component: <AgentIsRunningStep selectedAgent="SURGE" />,
          }
        }
      }
    }

    // PURGE

    const {
      amount,
      duration,
      primaryToken,
      secondaryToken,
      slippage,
      tradeSizeAmount,
      selectedSlippage,
    } = automationAgentData["PURGE"]
    switch (currentStep) {
      case "ONE": {
        const usdValueInputted =
          (primaryToken?.prices?.default || 0) * parseFloat(amount || "0")
        const isValueAllowed = usdValueInputted > MIN_USD_AMOUNT
        return {
          component: (
            <SelectTokenView
              title="Asset to Sell"
              subtitle="Select an asset and amount from your balances"
            >
              <BigAssetInputSelector
                warningText={
                  amount && !isValueAllowed
                    ? `Value should be more than $${MIN_USD_AMOUNT}`
                    : ""
                }
                showInputPresets
                inputValue={amount}
                setInputValue={(value) =>
                  updateAgentData("PURGE", {
                    amount: value,
                  })
                }
                selectedAsset={primaryToken}
                setSelectedAsset={async (asset) => {
                  updateAgentData("PURGE", {
                    primaryToken: asset,
                    amount: asset.balanceOf?.formatted || "",
                  })
                  const price = await getTokenPrice(asset.address, "base")
                  updateAgentData("PURGE", {
                    primaryToken: {
                      ...asset,
                      prices: { default: price.data || 0 },
                    },
                  })
                }}
                getMaxTokenBalanceAvailable={
                  getMaxTokenBalanceAvailableForPurge
                }
                availableAssets={eoaAssets.data}
              />
            </SelectTokenView>
          ),
          isNextButtonDisabled:
            !primaryToken || !amount || !isValueAllowed || !eoaAddress,
        }
      }

      case "TWO": {
        return {
          component: (
            <SelectTokenView
              title={`Exit [${primaryToken?.symbol || primaryToken?.name || ""}] to`}
            >
              <BigAssetSelector
                availableAssets={assets.filter(
                  (asset) => asset.address !== zeroAddress,
                )}
                showBalance={false}
                headerText="Select asset to sell"
                selectedAsset={secondaryToken}
                setSelectedAsset={(asset) => {
                  if (
                    asset.address.toLowerCase() ===
                    primaryToken?.address.toLowerCase()
                  ) {
                    dispatchToast({
                      id: "same-token-error",
                      title: "Token Selection Error",
                      description: {
                        value:
                          "Primary and secondary tokens cannot be the same.",
                      },
                      type: "error",
                    })
                    console.log(
                      "Error: Primary and secondary tokens cannot be the same.",
                    )
                    return
                  }

                  updateAgentData("PURGE", { secondaryToken: asset })
                }}
              />
            </SelectTokenView>
          ),
          isNextButtonDisabled: !secondaryToken,
        }
      }

      case "THREE": {
        return {
          component: (
            <TradeDetailsStep
              assetPrice={secondaryToken?.prices?.default || 0}
              amount={amount}
              logo={primaryToken?.logo || ""}
              onMaxTradeAmountSet={(value) => {
                updateAgentData("PURGE", { tradeSizeAmount: value })
              }}
              symbol={primaryToken?.symbol || primaryToken?.name || ""}
            />
          ),
          isNextButtonDisabled: !duration,
        }
      }

      case "FOUR": {
        return {
          component: (
            <FlexContainer
              justifyContent="space-between"
              height={100}
              style={{ minWidth: "60rem" }}
              flexDirection="column"
              gap={4.8}
            >
              <ReviewStep
                duration={duration}
                maxTradeSize={`${
                  amount
                    ? formatAmountWithOptions(tradeSizeAmount, {
                        maximumFractionDigits: 8,
                      })
                    : 0
                } ${primaryToken?.name}`}
                primaryTitle="Sell"
                secondaryTitle="Exit to"
                primaryTokenDetail={`${formatAmountWithOptions(amount)}${primaryToken?.name}`}
                secondaryTokenDetail={secondaryToken?.name || ""}
                primaryTokenLogo={primaryToken?.logo}
                secondaryTokenLogo={secondaryToken?.logo}
                slippage={slippage}
                selectedSlippage={selectedSlippage}
              />
              <ReviewStepButtonsSection />
            </FlexContainer>
          ),
          isNextButtonDisabled: true,
        }
      }

      case "RUNNING": {
        return {
          component: <AgentIsRunningStep selectedAgent="PURGE" />,
        }
      }
    }
  }, [
    currentStep,
    selectedAgent,
    automationAgentData,
    setSelectedAgent,
    goToNextStep,
    isMobile,
    assets,
    updateAgentData,
    accountAssets.data,
    getMaxTokenBalanceAvailableForSurge,
    eoaAssets.data,
    theme.colors.success,
    eoaAddress,
    getMaxTokenBalanceAvailableForPurge,
  ])

  usePolling(() => {
    eoaAddress && fetchEoaAssets(eoaAddress, assets)
  }, 5000)

  useEffect(() => {
    if (!eoaAddress) return
    fetchExistingSwapAgentConsole(eoaAddress)
  }, [eoaAddress, fetchExistingSwapAgentConsole])

  usePolling(() => {
    eoaAddress && fetchAutomations(eoaAddress, false)
    // we don't want to show the loading state for every time we poll
  }, 10000)

  useEffect(() => {
    if (!eoaAddress) return
    fetchAutomations(eoaAddress)
  }, [eoaAddress, fetchAutomations])

  usePolling(() => {
    const consoleAddress = existingSafeAddress
      ? existingSafeAddress
      : preComputedConsoleAddress

    consoleAddress && fetchConsoleBalances(assets, consoleAddress)
  }, 5000)

  useEffect(() => {
    const inputToken = selectedAgent === "SURGE" ? secondaryToken : primaryToken

    if (!eoaAddress || existingSafeAddress || !inputToken?.address) return

    fetchPreComputedConsoleAddress(
      eoaAddress,
      BASE_CHAIN_ID,
      inputToken.address,
    )
  }, [
    eoaAddress,
    fetchPreComputedConsoleAddress,
    existingSafeAddress,
    selectedAgent,
    secondaryToken,
    primaryToken,
  ])

  return {
    currentTab,
    stepData,
    goToNextStep,
    goToPreviousStep,
    setSelectedAgent,
    currentStep,
    selectedAgent,
    automations,
    resetAgentsData,
    permissionModalData,
  }
}
