import { motion } from "framer-motion";
import { type FC, useEffect, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";

import { Dropdown } from "@components/common/Dropdown";
import { MIcon } from "@components/common/MIcon";
import { useAccounts } from "@hooks/useAccounts";
import { useConfig } from "@hooks/useConfig";
import { toggleRecipientModal } from "@store/globalSlice";
import { setReceiverAddress, setSenderAddress } from "@store/quoteParamSlice";
import type { ReduxStateType } from "@store/types";
import { isSolana } from "@utils/isSolana";
import { replaceMetaMaskIcon } from "@utils/replaceMetaMask";
import { shortenAddress } from "@utils/shortenAddress";
import { twMerge } from "@utils/tailwindMerge";

interface WalletSelectorProps {
	type: "input" | "output";
	className?: string;
}

const defaultAccount = {
	label: "Select wallet",
	connectorIcon: undefined,
	address: "",
};

interface AccountItem {
	id: string;
	label: string;
	icon: string | undefined;
	type: string;
	onClick: () => void;
	isActive?: boolean;
}

const WalletSelector: FC<WalletSelectorProps> = ({ type, className }) => {
	const label = type === "input" ? "From" : "To";
	const { accounts, isAnyConnected } = useAccounts();
	const dispatch = useDispatch();
	const { eventHandlers } = useConfig();
	const { sender, receiver, fromChainId, toChainId } = useSelector(
		(state: ReduxStateType) => state.quoteParams,
	);

	const account = useMemo(() => {
		/**
		 * @description
		 * 1. If type is input, check if sender exists, if yes, check if sender is in accounts, if yes, return the account, else, return undefined
		 * 2. If type is output, check if receiver exists, if yes, check if receiver is in accounts, if yes, return the account, else, return undefined
		 */
		if (type === "input") {
			if (!sender) return defaultAccount;
			const account = accounts.find(
				(account) => account.address?.toLowerCase() === sender?.toLowerCase(),
			);
			if (!account) return defaultAccount;
			return {
				label: shortenAddress(account.address ?? ""),
				connectorIcon: account.connector?.icon,
				address: account.address,
				isCustomAddress: false,
			};
		}
		if (!receiver) return defaultAccount;
		const account = accounts.find(
			(account) => account.address?.toLowerCase() === receiver?.toLowerCase(),
		);
		// Custom recipient address
		if (!account) {
			return {
				label: shortenAddress(receiver),
				connectorIcon: undefined,
				address: receiver,
				isCustomAddress: true,
			};
		}
		return {
			label: shortenAddress(account.address ?? ""),
			connectorIcon: account.connector?.icon,
			address: account.address,
			isCustomAddress: false,
		};
	}, [type, accounts, sender, receiver]);

	// Auto-select sender as receiver when destination chain is not known
	useEffect(() => {
		if (type === "output" && toChainId === null && sender && !receiver) {
			dispatch(setReceiverAddress(sender));
		}
	}, [type, toChainId, sender, receiver, dispatch]);

	const accountItems = useMemo<Array<AccountItem>>(() => {
		const chainId = type === "input" ? fromChainId : toChainId;

		// For input type, chainId must be known
		if (type === "input" && chainId === null) return [];

		// For output type, if chainId is unknown, show fallback options only
		const accounts_: Array<AccountItem> =
			chainId !== null
				? accounts
						.filter(
							(account) =>
								account.chainType === (isSolana(chainId) ? "SVM" : "EVM"),
						)
						.map((account) => ({
							id: account.address ?? "",
							label: shortenAddress(account.address ?? ""),
							icon: account.connector?.icon,
							type: "account",
							onClick: () => {
								if (type === "input") {
									dispatch(setSenderAddress(account.address));
								} else {
									dispatch(setReceiverAddress(account.address));
								}
							},
							isActive:
								account.address?.toLowerCase() ===
								(type === "input" ? sender : receiver)?.toLowerCase(),
						}))
				: []; // Empty array when chainId is null

		if (type === "output") {
			const isCustomAccount =
				receiver &&
				!accounts.find(
					(account) =>
						account.address?.toLowerCase() === receiver?.toLowerCase(),
				);
			accounts_.push({
				id: "custom-recipient",
				label: isCustomAccount
					? shortenAddress(receiver)
					: "Add Custom Address",
				isActive: !!isCustomAccount,
				icon: "assignment",
				type: "custom",
				onClick: () => dispatch(toggleRecipientModal(true)),
			});

			// For output wallet selection, only show "Connect New Wallet" button if:
			// - Target chain is EVM but no EVM account is connected, OR
			// - Target chain is Solana (SVM) but no Solana account is connected
			// This prevents showing unnecessary connect buttons when user already has
			// a compatible wallet connected for the destination chain
			const isTargetChainSolana = isSolana(toChainId || 0);
			const hasMatchingAccountType = accounts.some(
				(account) => isSolana(account.chainId || 0) === isTargetChainSolana,
			);

			if (!hasMatchingAccountType) {
				accounts_.push({
					id: "connect-wallet",
					label: "Connect New Wallet",
					icon: "add",
					type: "custom",
					onClick: () =>
						eventHandlers?.onOpenWalletConnect?.(
							isTargetChainSolana ? "solana" : "eip155",
						),
				});
			}
		} else {
			accounts_.push({
				id: "connect-wallet",
				label: "Connect New Wallet",
				icon: "add",
				type: "custom",
				onClick: () =>
					eventHandlers?.onOpenWalletConnect?.(
						chainId !== null && isSolana(chainId) ? "solana" : "eip155",
					),
			});
		}

		return accounts_;
	}, [
		accounts,
		dispatch,
		eventHandlers?.onOpenWalletConnect,
		fromChainId,
		receiver,
		sender,
		toChainId,
		type,
	]);

	return (
		<div
			className={twMerge(
				"bn-flex bn-items-center bn-gap-2 bn-justify-between",
				className,
			)}
		>
			<p className="bn-text-sm bn-font-medium bn-text-secondary">{label}</p>
			{type === "input" && !isAnyConnected ? (
				<button
					type="button"
					className="bn-text-sm bn-font-medium bn-aeonik-font bn-text-secondary"
					onClick={() =>
						eventHandlers?.onOpenWalletConnect?.(
							fromChainId !== null && isSolana(fromChainId)
								? "solana"
								: "eip155",
						)
					}
				>
					Connect Wallet
				</button>
			) : (
				<Dropdown
					trigger={<WalletTriggerButton account={account} />}
					items={accountItems}
					position="left"
					className="bn-w-full"
					itemRenderer={({ index, handleSelect }) => {
						const item = accountItems[index] as AccountItem;
						if (item.type === "custom") {
							return (
								<CustomAccountButton
									item={item}
									index={index}
									handleSelect={handleSelect}
								/>
							);
						}
						return (
							<AccountItemButton
								item={item}
								index={index}
								handleSelect={handleSelect}
							/>
						);
					}}
				/>
			)}
		</div>
	);
};

export default WalletSelector;

interface Account {
	label: string;
	connectorIcon?: string;
	address?: string;
	isCustomAddress?: boolean;
}

const WalletTriggerButton = ({ account }: { account: Account }) => {
	return (
		<button type="button" className="bn-flex bn-items-center bn-gap-1 bn-h-4">
			{account.address && (
				<div className="bn-size-4">
					{account.connectorIcon ? (
						<img
							src={replaceMetaMaskIcon(account.connectorIcon)}
							alt="connector"
							className="bn-rounded-full bn-size-4"
						/>
					) : account.isCustomAddress ? (
						<MIcon name="assignment" classNames="bn-text-theme bn-text-base" />
					) : (
						<MIcon name="wallet" classNames="bn-text-theme bn-text-base" />
					)}
				</div>
			)}
			<p
				className={twMerge(
					"bn-text-sm bn-font-medium bn-aeonik-font",
					account.connectorIcon ? "bn-text-white" : "bn-text-theme",
					!account.address && "bn-text-secondary",
				)}
			>
				{account?.label}
			</p>
			<MIcon name="keyboard_arrow_down" classNames="bn-text-primary" />
		</button>
	);
};

const isLink = (link: string) => {
	// Remove leading newline if present, then check normally
	const cleanedLink = link.startsWith("\n") ? link.slice(1) : link;

	return (
		cleanedLink.startsWith("http") ||
		cleanedLink.startsWith("/") ||
		cleanedLink.startsWith("data:")
	);
};

const AccountItemButton = ({
	item,
	index,
	handleSelect,
}: {
	item: AccountItem;
	index: number;
	handleSelect: () => void;
}) => {
	return (
		<motion.button
			type="button"
			initial={{ opacity: 0 }}
			animate={{ opacity: 1 }}
			transition={{ delay: index * 0.05 }}
			className={twMerge(
				"bn-w-full bn-text-left bn-flex bn-items-center bn-gap-2 bn-bg-transparent bn-border-none bn-transition-colors",
				"bn-text-primary hover:bn-text-theme bn-cursor-pointer",
				item.isActive && "bn-text-theme",
			)}
			onClick={handleSelect}
		>
			{item.icon &&
				(isLink(item.icon) ? (
					<img
						src={replaceMetaMaskIcon(item.icon)}
						alt={item.id}
						className="bn-rounded-full bn-size-6"
					/>
				) : (
					<MIcon
						name={item.icon}
						classNames={twMerge("bn-text-lg", "bn-text-primary")}
					/>
				))}
			<span
				className={twMerge(
					"bn-flex-1 bn-text-sm bn-font-medium",
					item.isActive && "bn-text-theme",
				)}
			>
				{item.label}
			</span>
		</motion.button>
	);
};

const CustomAccountButton = ({
	item,
	index,
	handleSelect,
}: {
	item: AccountItem;
	index: number;
	handleSelect: () => void;
}) => {
	return (
		<motion.button
			type="button"
			initial={{ opacity: 0 }}
			animate={{ opacity: 1 }}
			transition={{ delay: index * 0.05 }}
			className={twMerge(
				"bn-w-full bn-text-left bn-flex bn-items-center bn-gap-2 bn-bg-transparent bn-border-none bn-transition-colors",
				"bn-text-primary hover:bn-text-theme bn-cursor-pointer bn-group",
			)}
			onClick={handleSelect}
		>
			{item.icon && (
				<div
					className={twMerge(
						"!bn-size-6 bn-min-w-6 bn-rounded-full bn-flex bn-justify-center bn-items-center bn-bg-[#373A3E] bn-transition-colors",
						"group-hover:bn-bg-theme",
						item.isActive && "bn-bg-theme",
					)}
				>
					<MIcon
						name={item.icon}
						classNames={twMerge(
							"bn-text-primary bn-text-base group-hover:bn-text-[#262420] bn-transition-colors",
							item.isActive && "bn-text-[#262420]",
						)}
					/>
				</div>
			)}
			<span className="bn-flex-1 bn-text-sm bn-font-medium bn-text-nowrap">
				{item.label}
			</span>
			<MIcon
				name={item.isActive ? "edit" : "keyboard_arrow_right"}
				classNames={twMerge(
					"bn-text-primary bn-text-sm",
					item.isActive && "bn-text-theme",
				)}
			/>
		</motion.button>
	);
};
