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

import { SwitchChain } from "@components/common/SwitchChain";
import { useToast } from "@providers/ToastProvider";
import { getCommonErrors } from "@utils/getCommonErrors";
import { useFetchQuote } from "../../hooks/apis/useFetchQuote";
import { useMappedChainData } from "../../hooks/useMappedChainData";
import { useTheme } from "../../hooks/useTheme";
import { setApprovalData } from "../../store/approvalSlice";
import { PERMIT2_ADDRESS } from "../../utils/constants";
import { getBorderRadius } from "../../utils/getBorderRadius";
import { ExplorerDataType, getExplorerLink } from "../../utils/getExplorerLink";
import { Button } from "../common/Button";
import { MIcon } from "../common/MIcon";
import { TokenIcon } from "../common/TokenIcon";

// biome-ignore format:
type Address = `0x${string}`;

export const Permit2Approval = () => {
	const mappedChainData = useMappedChainData();
	const { chainId } = useAccount();
	const dispatch = useDispatch();
	const theme = useTheme();
	const { writeContract, status, data: hash, error: contractError, isError: isContractError } = useWriteContract();
	const {showToast} = useToast()

	const { data: quoteData } = useFetchQuote();

	const {
		isLoading: isConfirming,
		isSuccess: isConfirmed
	} = useWaitForTransactionReceipt({
		hash,
	});

	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if (isConfirmed && dispatch && showToast) {
			dispatch(
				setApprovalData({
					isVisible: false,
					isApprovalGiven: true,
				}),
			);

			showToast("Token Approval Successful", `Approval given to ${token.symbol}`)
		}
	}, [isConfirmed]);

	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if (isContractError && dispatch && showToast) {
			dispatch(
				setApprovalData({
					isApprovalGiven: false,
				}),
			);

			const {name, shortMessage} = getCommonErrors(contractError)
			showToast("Token Approval Failed", shortMessage, 'error')
		}
	}, [isContractError]);

	if (!quoteData) return null;
	const primaryInput = quoteData?.primaryInput;

	const chain = mappedChainData?.[primaryInput.chainId];
	const chainUrl = chain?.icon;
	const token = primaryInput.token;

	const contractAddress =
		chain &&
		getExplorerLink(
			chain?.explorers?.[0],
			PERMIT2_ADDRESS,
			ExplorerDataType.ADDRESS,
		);

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

		if (isConfirming) return "Approving...";

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

	async function approveToken() {
		writeContract({
			abi: erc20Abi,
			address: primaryInput?.token.address as Address,
			functionName: "approve",
			chainId: primaryInput?.chainId,
			args: [PERMIT2_ADDRESS, maxUint256],
		});
	}

	return (
		<>
			<div className="bn-relative bn-h-[56px] bn-w-[56px] bn-mx-auto bn-mb-4">
				<TokenIcon url={token.logoURI} classNames="bn-h-full bn-w-full" />
				{chainUrl && (
					<TokenIcon
						url={chainUrl}
						classNames="bn-w-7 bn-h-7 bn-absolute bn-bottom-0 -bn-right-2"
					/>
				)}
			</div>

			<div className="bn-mb-4">
				<p className="bn-text-center bn-text-primary bn-font-medium bn-text-xl bn-mb-1">
					Give token approval to {token.symbol} on {chain?.name}
				</p>
				<p className="bn-text-secondary bn-font-normal bn-text-sm bn-text-center">
					Allow Permit2, a secure contract to transfer a pre-defined amount of tokens on
					your behalf.{" "}
					<a
						href={contractAddress}
						className="bn-text-accent bn-font-medium bn-no-underline"
						target="_blank"
						rel="noreferrer"
					>
						View Contract
					</a>
				</p>
			</div>

			<div
				className="bn-bg-layer-2 bn-mb-4"
				style={{ borderRadius: getBorderRadius(theme.borderRadius, 8) }}
			>
				<div className="bn-py-[18px] bn-px-[2.5px] bn-flex bn-items-center bn-justify-between">
					{benefits.map((item) => (
						<Permit2Benefit key={item.icon} data={item} />
					))}
				</div>
				<div className="bn-px-2 bn-py-2.5 bn-border-0 bn-border-t bn-border-solid bn-border-primary bn-flex bn-items-center">
					<MIcon
						name="verified_user"
						classNames="bn-text-accent bn-text-[24px] bn-flex-shrink-0"
					/>
					<p className="bn-ml-2 bn-text-primary bn-font-medium bn-text-xs">
						Recommended: Give max token approval by{" "}
						<span className="bn-text-accent">clicking site suggestion</span> in your wallet
						pop-up.
					</p>
				</div>
			</div>

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

interface Benefit {
	label: string;
	icon: string;
}

const benefits: Benefit[] = [
	{
		label: "Approve token only once",
		icon: "check",
	},
	{
		label: "Save gas fee on approvals",
		icon: "attach_money",
	},
	{
		label: "Change approval anytime",
		icon: "edit",
	},
];

const Permit2Benefit = ({ data }: { data: Benefit }) => {
	// @fixme: color token
	return (
		<div className="bn-flex bn-flex-col bn-items-center bn-max-w-[103px]">
			<div className="bn-w-9 bn-h-9 bn-rounded-full bn-bg-layer-3 bn-flex bn-items-center bn-justify-center">
				<div className="bn-bg-white bn-w-[25px] bn-h-[25px] bn-rounded-full bn-flex bn-items-center bn-justify-center">
					<MIcon name={data.icon} classNames="bn-text-xl" />
				</div>
			</div>
			<p className="bn-text-center bn-mt-2 bn-text-xs bn-text-primary bn-font-normal">
				{data.label}
			</p>
		</div>
	);
};
