import { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

import { useDebounce } from "@uidotdev/usehooks";
import { isValidENS } from "@utils/isValidENS.ts";
import { usePasteFromClipboard } from "../hooks/usePasteFromClipboard";
import { useTheme } from "../hooks/useTheme";
import {
	type Validity,
	useValidateAddress,
} from "../hooks/useValidateAddress.ts";
import { toggleRecipientModal } from "../store/globalSlice";
import { setReceiverAddress, setReceiverENS } from "../store/quoteParamSlice";
import type { ReduxStateType } from "../store/types";
import { getBorderRadius } from "../utils/getBorderRadius";
import { Button } from "./common/Button.tsx";
import { MIcon } from "./common/MIcon.tsx";
import { ModalHeader } from "./common/ModalHeader.tsx";
import { SlideInPanel } from "./common/SlideInPanel.tsx";
import { SquaredCheckbox } from "./common/SquaredCheckbox.tsx";

// @fixme: color tokens
// @todo: need to make recipient address mandatory for smart wallets

interface AddressInputProps {
	value: string;
	onChange: (value: string) => void;
	disabled?: boolean;
	onPaste: () => void;
	onClear: () => void;
	hasAddress: boolean;
}

const AddressInput: React.FC<AddressInputProps> = ({
	value,
	onChange,
	disabled,
	onPaste,
	onClear,
	hasAddress,
}) => {
	const theme = useTheme();

	return (
		<div
			className="bn-h-[52px] bn-border bn-border-solid bn-border-primary bn-pl-4 bn-pr-2.5 bn-relative bn-flex bn-items-center bn-justify-between bn-bg-layer-2"
			style={{ borderRadius: getBorderRadius(theme.borderRadius, 8) }}
		>
			<input
				className="bn-bg-transparent bn-text-sm bn-font-medium bn-text-primary bn-h-full bn-w-full bn-border-0 bn-mr-3 bn-overflow-ellipsis"
				value={value}
				onChange={(e) => onChange(e.target.value)}
				placeholder="Enter Destination Address"
				spellCheck={false}
				id="bn-receiver-address"
				disabled={disabled}
				aria-label="Recipient address input"
			/>
			{!disabled && (
				hasAddress ? (
					<button
						className="bn-h-6 bn-w-6 bn-border-0 bn-flex bn-items-center bn-justify-center bn-cursor-pointer bn-text-primary bn-bg-transparent"
						type="button"
						onClick={onClear}
						aria-label="Clear address"
					>
						<MIcon name="backspace" />
					</button>
				) : (
					<PasteButton onClick={onPaste} />
				)
			)}
		</div>
	);
};

interface ValidationBoxProps {
	status: Validity;
}

const ValidationBox: React.FC<ValidationBoxProps> = ({ status }) => {
	const getMsg = useCallback(() => {
		if (status.isContract) return "Smart contract";
		if (status.isSender)
			return "Recipient address cannot be same as connected wallet";
		if (!status.isValid) return "Invalid wallet address";
		return null;
	}, [status]);

	const message = getMsg();
	if (!message) return null;

	const style = `bn-pl-1 bn-text-sm bn-font-normal bn-mt-2 ${
		status.isContract ? "bn-text-accent" : "bn-text-fail"
	}`;

	return <p className={style}>{message}</p>;
};

interface PasteButtonProps {
	onClick: () => void;
}

const PasteButton: React.FC<PasteButtonProps> = ({ onClick }) => {
	const theme = useTheme();
	return (
		<button
			type="button"
			className="bn-px-4 bn-py-1.5 bn-text-accent bn-text-sm bn-font-medium bn-bg-accent bn-border-0 bn-cursor-pointer"
			style={{ borderRadius: getBorderRadius(theme.borderRadius, 8) }}
			onClick={onClick}
			aria-label="Paste address from clipboard"
		>
			Paste
		</button>
	);
};

export const RecipientAddressModal: React.FC = () => {
	const dispatch = useDispatch();
	const isOpen = useSelector(
		(state: ReduxStateType) => state.global.showRecipientModal,
	);
	const toChainId = useSelector(
		(state: ReduxStateType) => state.quoteParams.toChainId,
	);
	const receiver = useSelector(
		(state: ReduxStateType) => state.quoteParams.receiver,
	);

	useEffect(() => {
		if(!receiver){
			setValue("");
			setDisclaimer(false);
		}
	}, [receiver])

	const [value, setValue] = useState<string>("");
	const [disclaimer, setDisclaimer] = useState<boolean>(false);

	const { state: copiedAddress, pasteFromClipboard } = usePasteFromClipboard();
	const debouncedAddress = useDebounce(value, 300);

	const { state: addressStatus, address } = useValidateAddress({
		value: debouncedAddress,
		toChainId: toChainId ?? undefined,
	});

	const closePanel = useCallback(() => {
		dispatch(toggleRecipientModal(false));
	}, [dispatch]);

	const dispatchRecipientAddress = useCallback(() => {
		if (!address) return;
		
		dispatch(setReceiverAddress(address));

		if (isValidENS(value)) {
			dispatch(setReceiverENS(value));
		} else {
			dispatch(setReceiverENS(null));
		}
		closePanel();
	}, [address, value, dispatch, closePanel]);

	const removeRecipientAddress = useCallback(() => {
		setValue("");
		setDisclaimer(false);
		dispatch(setReceiverAddress(""));
		closePanel();
	}, [dispatch, closePanel]);

	useEffect(() => {
		if (copiedAddress) {
			setValue(copiedAddress);
		}
	}, [copiedAddress]);

	useEffect(() => {
		setValue("");
	}, []);

	const modalTitle = useMemo(() => 
		receiver ? "Edit Recipient Address" : "Add Recipient Address",
		[receiver]
	);

	const isConfirmDisabled = useMemo(() => 
		!address || !disclaimer || !addressStatus.isValid || addressStatus.isSender,
		[address, disclaimer, addressStatus]
	);

	return (
		<SlideInPanel isVisible={isOpen} closePanel={closePanel}>
			<ModalHeader 
				label={modalTitle} 
				closeModal={closePanel} 
				subText="Swap and send tokens to another address" 
				classNames="bn-border-0"
			/>

			<div className="bn-px-4 bn-mt-2">
				<AddressInput
					value={value}
					onChange={setValue}
					disabled={!!receiver}
					onPaste={pasteFromClipboard}
					onClear={() => setValue("")}
					hasAddress={!!address}
				/>

				{address && <ValidationBox status={addressStatus} />}
			</div>

			{receiver ? (
				<div className="bn-p-4">
					<Button
						onClick={removeRecipientAddress}
						label="Remove Recipient Address"
						classNames="bn-bg-fail"
					/>
				</div>
			) : (
				<div className="bn-p-4">
					<div className="bn-flex bn-items-center bn-mb-4">
						<SquaredCheckbox
							id="recipient-address-checkbox"
							active={disclaimer}
							setActive={setDisclaimer}
						/>
						<p className="bn-ml-1.5 bn-text-secondary bn-font-normal bn-text-sm">
							The address is correct and not an exchange wallet.{" "}
							<span className="bn-text-fail">
								Tokens sent to the wrong address can't be retrieved.
							</span>
						</p>
					</div>

					<Button
						onClick={dispatchRecipientAddress}
						label="Confirm Recipient Address"
						disabled={isConfirmDisabled}
					/>
				</div>
			)}
		</SlideInPanel>
	);
};
