import { useEffect, useMemo, useState } from "react";
import { isAddress } from "viem";
import { normalize } from "viem/ens";
import { useBytecode, useEnsAddress } from "wagmi";

import { isPDA } from "@utils/isPDA";
import { isPublicKey } from "@utils/isPublicKey";
import { isSolana } from "@utils/isSolana";
import { isValidENS } from "@utils/isValidENS";
import { useAccounts } from "./useAccounts";

export interface Validity {
	isValid: boolean;
	isContract: boolean;
	isChecking: boolean;
}

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

/**
 * Checks the validity of ENS or Account Address
 */
export const useValidateAddress = ({
	value,
	toChainId,
}: {
	value: string;
	toChainId?: number;
}) => {
	const [address, setAddress] = useState<string>();

	const { accounts } = useAccounts();

	const isRecipientChainSolana = useMemo(
		() => (toChainId === undefined ? false : isSolana(toChainId)),
		[toChainId],
	);

	let senderAddress: string | undefined;
	let activeChainId: number | undefined;

	for (const account of accounts) {
		if (account.chainType === "SVM" && isRecipientChainSolana) {
			senderAddress = account.address;
			activeChainId = account.chainId;
		}

		if (account.chainType === "EVM" && !isRecipientChainSolana) {
			senderAddress = account.address;
			activeChainId = account.chainId;
		}
	}

	// getting ensAddress if value is in valid ens format
	const { data: ensAddress, isPending } = useEnsAddress({
		name: isValidENS(value) ? normalize(value) : "",
		chainId: toChainId,
		query: {
			enabled: isValidENS(value) && Boolean(toChainId) && !isRecipientChainSolana,
		},
	});

	useEffect(() => {
		if (!isValidENS(value) || !isPending) setAddress(ensAddress || value);
	}, [ensAddress, value, isPending]);

	const result = useBytecode({
		address: address as Address,
		chainId: toChainId,
	});

	const state = useMemo(() => {
		if (!address) {
			return {
				isValid: false,
				isContract: false,
				isChecking: false,
			};
		}

		if (isRecipientChainSolana) {
			return {
				isValid: isPublicKey(address),
				isContract: isPDA(address),
				isChecking: false,
			};
		}

		const _isAddress = address ? isAddress(address.toLowerCase()) : false;

		return {
			isValid: _isAddress,
			isContract: Boolean(result?.data),
			isChecking: isValidENS(value) ? isPending : false,
		};
	}, [address, result, value, isPending, isRecipientChainSolana]);

	return { state, address };
};
