import { useDispatch, useSelector } from "react-redux";

import type { FormattedQuoteResponse } from "@hooks/apis/common/quote/types";
import { useActiveRoute } from "@hooks/apis/common/quote/useActiveRoute";
import { isAutoQuote, isManualQuote } from "@hooks/apis/common/quote/useQuote";
import { useAccounts } from "@hooks/useAccounts";
import { useIsAbstractNetwork } from "@hooks/useIsAbstractNetwork";
import { useTokenBalance } from "@hooks/useTokenBalance";
import type { ReduxStateType } from "@store/types";
import { getPairsNetworkFromRoute } from "@utils/getPairsNetworkFromRoute";
import { isDummyAddress } from "@utils/isDummyAddress";
import { isWrapUnwrapCase } from "@utils/isWrapUnwrapCase";
import {
	ScreenTab,
	setScreenTab,
	toggleRecipientModal,
} from "../store/globalSlice";
import { SendNativeTransaction } from "./Review/Auto/SendNativeTransaction";
import { Button } from "./common/Button";

function isBalanceAvailable(
	balance: string | bigint | undefined,
	amount: string,
) {
	if (!balance || !amount) return null;

	const amountBn = BigInt(amount);
	const balanceBn = BigInt(balance);

	return amountBn <= balanceBn;
}

export const ActionButton = () => {
	const dispatch = useDispatch();
	const { accounts } = useAccounts();
	const {
		amounts,
		fromTokens: activeFromTokens,
		toTokens,
		receiver,
	} = useSelector((state: ReduxStateType) => state.quoteParams);
	const { data: activeRoute, isLoading, isRefetching } = useActiveRoute();

	const evmAccount = accounts.find((account) => account.chainType === "EVM");

	const amount = amounts?.[0];

	const { balance } = useTokenBalance({ token: activeFromTokens?.[0] });
	const _isBalanceAvailable = isBalanceAvailable(balance, amount);

	// to check native balance for refuel transfers (needed for manual routes)
	const manaulRefuel = isManualQuote(activeRoute) && activeRoute?.refuel;
	const { balance: nativeTokenBalance } = useTokenBalance({
		token: manaulRefuel ? manaulRefuel.input.token : undefined,
	});
	const enoughTokensToRefuel = manaulRefuel
		? hasEnoughTokensToRefuel({
				activeRoute,
				balance: nativeTokenBalance.toString(),
			})
		: false;

	const getLabel = () => {
		if (activeRoute) {
			if (!_isBalanceAvailable) return "Insufficient Balance";

			// for refuel
			if (manaulRefuel) {
				const isNativeBalanceAvailable = hasEnoughTokensToRefuel({
					activeRoute,
					balance: nativeTokenBalance.toString(),
				});
				if (!isNativeBalanceAvailable) {
					return "Insufficient Native Token";
				}
			}
		}

		if (!_isBalanceAvailable && Boolean(activeRoute)) return "Insufficient Balance";
		if (!activeRoute && !(isLoading || isRefetching)) {
			if (amount && activeFromTokens?.length && toTokens?.length)
				return "No Quote Found";
		}

		return "Swap";
	};

	function openSelectRecipientWallet() {
		dispatch(toggleRecipientModal(true));
	}

	function openReview() {
		dispatch(setScreenTab(ScreenTab.REVIEW));
	}

	// Recipient address mandatory incase of abstract network
	const isAbstractNetwork = useIsAbstractNetwork();

	// To add recipient address
	if (isAbstractNetwork && !receiver)
		return (
			<Button
				label="Select Recipient Address"
				classNames="bn-mt-4"
				onClick={() => {
					dispatch(toggleRecipientModal(true));
				}}
			/>
		);
	if (
		activeRoute &&
		isWrapUnwrapCase(activeRoute) &&
		isAutoQuote(activeRoute) &&
		_isBalanceAvailable
	) {
		return (
			<div className="bn-mt-4">
				<SendNativeTransaction quoteData={activeRoute} />
			</div>
		);
	}

	const senderIsDummyAddress = isDummyAddress(activeRoute?.sender ?? "");
	const receiverIsDummyAddress = isDummyAddress(activeRoute?.receiver ?? "");

	// If sender address is dummy, that mean the required wallet to execute the tx isn't connected; so, no need to figure out recipient wallet
	if (activeRoute && !senderIsDummyAddress) {
		const { isSingleNetwork } = getPairsNetworkFromRoute(activeRoute);

		if (!isSingleNetwork && receiverIsDummyAddress) {
			return (
				<Button
					label={"Select Recipient Wallet"}
					onClick={openSelectRecipientWallet}
					classNames="bn-mt-4"
					id="select-recipient-wallet-homescreen-btn"
				/>
			);
		}
	}

	// disabling action button if the receiver address is dummy address

	const disableButton =
		isLoading ||
		!activeRoute ||
		!_isBalanceAvailable ||
		isRefetching ||
		senderIsDummyAddress ||
		(manaulRefuel && !enoughTokensToRefuel) ||
		receiverIsDummyAddress ||
		(isAbstractNetwork && !receiver); // receipient address is mandatory for abstract network

	return (
		<Button
			label={getLabel()}
			onClick={openReview}
			classNames="bn-mt-4"
			disabled={disableButton}
			id="swap-homescreen-btn"
		/>
	);
};

/**
 * to check if sufficient native token is avaialbe for refuel as add-on (only for manual routes)
 * if source token is native, adding the amounts
 */
const hasEnoughTokensToRefuel = ({
	activeRoute,
	balance,
}: {
	activeRoute: FormattedQuoteResponse;
	balance: string;
}) => {
	if (!activeRoute?.refuel || isAutoQuote(activeRoute)) return;

	const { refuel, primaryInput } = activeRoute;
	const refuelInput = refuel.input;

	let totalAmount = BigInt(refuelInput.amount);

	// if source token is same as native token, add the amounts
	const isSourceNative =
		primaryInput.token.address.toLowerCase() ===
		refuelInput.token.address.toLowerCase();
	if (isSourceNative) {
		totalAmount = BigInt(primaryInput.amount) + BigInt(refuelInput.amount);
	}

	return isBalanceAvailable(balance, totalAmount.toString());
};
