import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { type Address, erc20Abi } from "viem";
import {
	useAccount,
	useWaitForTransactionReceipt,
	useWriteContract,
} from "wagmi";

import { Button } from "@components/common/Button";
import { SwitchChain } from "@components/common/SwitchChain";
import { useActiveRoute } from "@hooks/apis/common/quote/useActiveRoute";
import { isManualQuote } from "@hooks/apis/common/quote/useQuote";
import { useConfig } from "@hooks/useConfig";
import { useToast } from "@providers/ToastProvider";
import { setApprovalData } from "@store/approvalSlice";
import { setIsFetchingDisabled } from "@store/quoteParamSlice";
import { getCommonErrors } from "@utils/getCommonErrors";

export const ApproveToken = ({
	checkingApproval,
	isLoading,
}: {
	checkingApproval: boolean;
	isLoading: boolean;
}) => {
	const { chainId } = useAccount();
	const dispatch = useDispatch();
	const bungeeConfig = useConfig();
	const {
		writeContract,
		data: hash,
		status,
		error: contractError,
		isError: isContractError,
	} = useWriteContract();
	const { showToast } = useToast();

	const { data: activeRoute } = useActiveRoute();

	/** Checking Tx Receipt to make sure the tx is not reverted on chain */
	const {
		data: receiptData,
		error: txReceiptError,
		isError: isTxReceiptError,
	} = useWaitForTransactionReceipt({
		hash,
		chainId: activeRoute?.primaryInput.token.chainId ?? chainId,
		query: {
			enabled: Boolean(hash),
			retry: 5,
			retryDelay: 3000,
		},
	});

	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if (receiptData?.status === "success" && showToast) {
			// Decode the approved amount from hex
			const approvedAmountHex = receiptData.logs[0].data;
			const approvedAmount = BigInt(approvedAmountHex); // Convert hex to BigInt

			// Check if approved amount is greater than or equal to approvalAmount
			if (approvedAmount >= BigInt(approvalAmount)) {
				const toastTitle = "Token Approval Successful";
				// biome-ignore format:
				const toastMsg = `Approval given to ${token.symbol}`;

				showToast(toastTitle, toastMsg);

				bungeeConfig?.eventHandlers?.onEvent?.("success", {
					title: toastTitle,
					message: toastMsg,
					action: "APPROVAL",
				});

				dispatch(
					setApprovalData({
						isVisible: false,
						isApprovalGiven: true,
					}),
				);
			} else {
				const toastTitle = "Token Approval Failed";
				// biome-ignore format:
				const toastMsg = `Approved amount is less than required for ${token.symbol}`;

				showToast(toastTitle, toastMsg, "error");

				bungeeConfig?.eventHandlers?.onEvent?.("warning", {
					title: toastTitle,
					message: toastMsg,
					action: "APPROVAL",
				});

				dispatch(
					setApprovalData({
						isVisible: false,
						isApprovalGiven: false,
					}),
				);
			}

			dispatch(setIsFetchingDisabled(false));
		}
	}, [receiptData]);

	/** @todo fix the error messages. check if getCommonErrors still works */
	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if ((isContractError || isTxReceiptError) && showToast) {
			dispatch(
				setApprovalData({
					isVisible: false,
					isApprovalGiven: false,
				}),
			);
			const error = isContractError ? contractError : txReceiptError;
			if (error) {
				const { name, shortMessage } = getCommonErrors(error);
				bungeeConfig?.eventHandlers?.onEvent?.("error", {
					title: name ?? "Token approval failed",
					message: shortMessage,
					action: "APPROVAL",
				});
				showToast(name ?? "Token Approval Failied", shortMessage, "error");
			}
		}
	}, [
		contractError,
		txReceiptError,
		isTxReceiptError,
		isContractError,
		dispatch,
	]);

	if (!activeRoute || !activeRoute?.approvalData) return <></>;

	const { primaryInput } = activeRoute || {};
	const token = primaryInput.token;

	function getButtonLabel() {
		if (checkingApproval) return "Checking for approval";

		if (status === "pending") {
			return "Confirm in wallet";
		}

		//biome-ignore format:
		return `Approve ${token.symbol}`;
	}

	const targetAddress = activeRoute?.approvalData.spenderAddress as Address;
	const approvalAmount = activeRoute?.approvalData.amount;

	async function approveToken() {
		dispatch(setIsFetchingDisabled(true));
		openApproval();

		writeContract({
			abi: erc20Abi,
			address: primaryInput?.token.address as Address,
			functionName: "approve",
			chainId: primaryInput.token.chainId,
			args: [targetAddress, BigInt(approvalAmount)],
		});
	}

	const openApproval = () => {
		dispatch(
			setApprovalData({
				isVisible: true,
				approvalType: isManualQuote(activeRoute) ? "erc20" : "permit2",
			}),
		);
	};

	return (
		<>
			{chainId !== primaryInput?.token.chainId ? (
				<SwitchChain switchTo={primaryInput?.token.chainId} />
			) : (
				<Button
					label={getButtonLabel()}
					onClick={approveToken}
					disabled={status === "pending" || isLoading}
					isLoading={status === "pending" || isLoading}
				/>
			)}
		</>
	);
};
