import CurrencyInputPanel from '@components/CurrencyInputPanel';
import SwapRoute from '@components/SwapRoutes';
import SwitchCurrencyInput from '@components/SwitchCurrencyInput';
import { ToastError, ToastWarning } from '@components/Toast';
import { useEthersSigner } from '@hooks/useEthersSigner';
import { Route as lifiRoute } from '@lifi/sdk';
import { ConnectButton } from '@rainbow-me/rainbowkit';
import {
  IToken,
  destinationToken,
  originToken,
  slippage,
  tokenAtom,
} from '@store/store';
import { Button } from '@ui/Button/Button';
import Container from '@ui/Container/Container';
import Flex from '@ui/Flex/Flex';
import { Skeleton } from '@ui/Skeleton';
import Spinner from '@ui/Spinner/Spinner';
import { calculateNumberDecimalContract } from '@utils/bignumber';
import swap from '@utils/swap/swap';
import { IRouteInfo } from '@utils/swap/types';
import { trpc } from '@utils/trpc';
import { Signer } from 'ethers';
import { useAtom, useAtomValue } from 'jotai';
import { useEffect, useMemo, useState } from 'react';
import { CountdownCircleTimer } from 'react-countdown-circle-timer';
import { toast } from 'react-hot-toast';
import { useDebounce } from 'react-use';
import { useAccount, useBalance, useNetwork, useSwitchNetwork } from 'wagmi';

interface ISwap {
  amountIn: string;
  fromToken: IToken;
  toToken: IToken;
  address: `0x${string}`;
}

export default function Swap() {
  const tokenList = useAtomValue(tokenAtom);

  const [fromToken, setFormToken] = useAtom(originToken);
  const [toToken, setToToken] = useAtom(destinationToken);
  const [currentSlippage] = useAtom(slippage);

  const [isUserConnected, setIsUserConnected] = useState<boolean>();

  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [swapRoute, setSwapRoute] = useState<IRouteInfo[]>();
  const [amount, setAmount] = useState<string>();
  const [selectedRoute, setSelectedRoute] = useState<IRouteInfo>();
  const [refreshRoute, setRefreshRoute] = useState<boolean>(false);

  const { address, isConnected } = useAccount();
  const { chain } = useNetwork();
  const { switchNetwork } = useSwitchNetwork();
  const { data: fromTokenBalance } = useBalance({
    address: address,
    token:
      fromToken?.detail?.address.toLowerCase() ===
      '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'.toLowerCase()
        ? undefined
        : (fromToken?.detail?.address as `0x${string}`),
    chainId: fromToken?.detail?.chainId,
    watch: true,
  });
  const { data: toTokenBalance } = useBalance({
    address: address,
    token:
      toToken?.detail?.address.toLowerCase() ===
      '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'.toLowerCase()
        ? undefined
        : (toToken?.detail?.address as `0x${string}`),
    chainId: toToken?.detail?.chainId,
    watch: true,
  });

  const signer = useEthersSigner();

  useEffect(() => setIsUserConnected(isConnected), [isConnected]);

  const handleSwap = useMemo(() => new swap(), []);
  const mutation = trpc.swap.routes.useMutation({
    onMutate: () => {
      setSwapRoute(undefined);
      setSelectedRoute(undefined);
    },
    onSuccess: (data) => {
      setSelectedRoute(data[0]);
      setSwapRoute(data);
    },
    onError: (error) => {
      toast.custom((t) => (
        <ToastError
          title="Failed To Fetch Routes. Please try again."
          dismiss={() => toast.dismiss(t.id)}
        />
      ));
    },
  });

  useDebounce(
    () => {
      if (!amount || !fromToken || !toToken || !address) return;
      const convertedAmountIn = calculateNumberDecimalContract(
        amount,
        fromToken.detail?.decimals!
      );
      getRoute({ amountIn: convertedAmountIn, fromToken, toToken, address });
    },
    500,
    [amount, fromToken, toToken, address, refreshRoute]
  );

  const getRoute = ({ amountIn, fromToken, toToken, address }: ISwap) => {
    mutation.mutate({
      fromToken: fromToken.detail,
      toToken: toToken.detail,
      amount: amountIn,
      address: address,
      slippage: currentSlippage,
    });
  };

  const switchChainHook = async (
    requiredChainId: number
  ): Promise<Signer | undefined> => {
    switchNetwork?.(requiredChainId);

    return signer as unknown as Promise<Signer | undefined>;
  };

  const execute = (selectedRoute: IRouteInfo | undefined) => {
    if (
      !selectedRoute ||
      !signer ||
      !amount ||
      !fromToken ||
      !toToken ||
      !address
    )
      return;

    setIsLoading(true);
    const convertedAmountIn = calculateNumberDecimalContract(
      amount,
      fromToken.detail.decimals!
    );
    const { type, response } = selectedRoute;
    switch (type) {
      case 'QuoteSimulationResult':
        handleSwap
          .executeRangoSwap(signer, {
            fromToken: fromToken.detail!,
            toToken: toToken.detail!,
            amount: convertedAmountIn,
            address: address,
            slippage: currentSlippage,
          })
          .then((res) => {
            setIsLoading(false);
          })
          .catch((e) => {
            setIsLoading(false);
          });
        break;
      case 'lifiRoute':
        handleSwap
          .executeLifiSwap(signer, response as lifiRoute)
          .then((res) => {
            setIsLoading(false);
          })
          .catch((e) => {
            // if (
            //   e.includes("500") ||
            //   e.toLowerCase().includes("network error")
            // ) {
            //   toast.custom((t) => (
            //     <ToastWarning
            //       title="Try Again"
            //       dismiss={() => toast.dismiss(t.id)}
            //     />
            //   ));
            // }

            // if (e.includes("exchange rate")) {
            //   toast.custom((t) => (
            //     <ToastWarning
            //       title="The price has been change please press the 'Refresh' button"
            //       dismiss={() => toast.dismiss(t.id)}
            //     />
            //   ));
            // }

            setIsLoading(false);
          });
        break;
      // case 'ISwapExactInSymbiosis':
      //   handleSwap
      //     .executeSymbiosisSwap(signer, response as ISwapExactInSymbiosis)
      //     .then((res) => {
      //       setIsLoading(false);
      //     })
      //     .catch((e) => {
      //       setIsLoading(false);
      //     });
      //   break;
    }
  };

  const handleSwitchNetwork = () => {
    toast.custom((t) => (
      <ToastWarning
        title="Switch Your Network"
        dismiss={() => toast.dismiss(t.id)}
      />
    ));
    switchNetwork?.(fromToken?.detail.chainId);
  };

  const insufficientBalance = Boolean(
    Number(fromTokenBalance?.formatted) < Number(amount)
  );

  return (
    <Container customStyle="h-full flex items-center justify-center">
      <Flex customStyle="max-w-lg" alignItems="center" direction="column">
        <h1 className="mb-5 text-4xl font-bold text-wheat-300">
          SWAP & BRIDGE
        </h1>
        <CurrencyInputPanel
          tokenList={tokenList}
          selectedCurrency={fromToken}
          setToken={setFormToken as any}
          currencyBalance={fromTokenBalance?.formatted}
          setAmount={setAmount}
          amount={amount}
          placeholder="Enter amount"
        />
        <SwitchCurrencyInput
          setRefreshRoute={() => setRefreshRoute(!refreshRoute)}
        />
        <CurrencyInputPanel
          tokenList={tokenList}
          setAmount={() => {}}
          placeholder="0.0"
          selectedCurrency={toToken}
          setToken={setToToken as any}
          currencyBalance={toTokenBalance?.formatted}
          amount={selectedRoute ? selectedRoute.amountOut : ''}
          disabled
        />

        {mutation.isLoading ? (
          <Skeleton />
        ) : (
          selectedRoute &&
          swapRoute && (
            <SwapRoute
              destinationToken={toToken!}
              routes={swapRoute}
              selectedRoute={selectedRoute}
              changeRoute={setSelectedRoute}
            >
              <CountdownCircleTimer
                isPlaying={
                  !amount || !fromToken || !toToken || !address || isLoading
                    ? false
                    : true
                }
                duration={60}
                colors="#aaa"
                size={15}
                trailColor="rgba(0,0,0,0)"
                strokeWidth={2}
                onComplete={() => {
                  setRefreshRoute(!refreshRoute);
                  return { shouldRepeat: true };
                }}
              />
            </SwapRoute>
          )
        )}

        {!isUserConnected ? (
          <div className="my-5">
            <ConnectButton />
          </div>
        ) : isLoading ? (
          <Button disable={true} width="half" intent="disablePrimary">
            <Flex width="auto" justifyContent="center" alignItems="center">
              <Spinner />
              Processing...
            </Flex>
          </Button>
        ) : (
          <Button
            disable={!insufficientBalance || !selectedRoute ? true : false}
            onClick={() =>
              chain?.id !== fromToken?.detail.chainId
                ? handleSwitchNetwork()
                : execute(selectedRoute!)
            }
            width="half"
          >
            {insufficientBalance
              ? `Insufficient ${fromToken?.detail.symbol} balance`
              : 'Swap'}
          </Button>
        )}
      </Flex>
    </Container>
  );
}
