import { Connection } from "@solana/web3.js";
import { useQuery } from "@tanstack/react-query";
import { isSolana } from "@utils/isSolana";
import { type Address, decodeAbiParameters, parseAbiParameters } from "viem";
import { useTransactionReceipt } from "wagmi";
import { useConfig } from "./useConfig";
import { useSearch } from "./useSearch";
import { useSupportedTokens } from "./useSupportedTokens";

interface ParsedInstructionInfo {
	destination: string;
	mint: string;
	multisigAuthority: string;
	signers: string[];
	source: string;
	tokenAmount: {
		amount: string;
		decimals: number;
		uiAmount: number;
		uiAmountString: string;
	};
}

interface ParsedInstruction {
	program: string;
	programId: string;
	parsed: Record<"info", ParsedInstructionInfo>;
}

// The hexadecimal hash for the ERC-20 Transfer event
export const ERC20_TRANSFER_SIG =
	"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";

export const ERC20_WITHDRAWAL_SIG =
	"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65";

export const REQUEST_REFUNDED_SIG =
	"0x3754b0090c75d1f0866f0d41983f3eadd3b0de510c67e67e0ad24a94b756d9f1";

export const useTransferLog = ({
	hash,
	chainId,
	enabled,
	targetTokenAddress,
	signatures = [ERC20_TRANSFER_SIG, ERC20_WITHDRAWAL_SIG, REQUEST_REFUNDED_SIG],
}: {
	hash: string;
	chainId: number;
	enabled?: boolean;
	targetTokenAddress?: string;
	signatures?: string[];
}) => {
	const isEvmEnabled = Boolean(enabled && !isSolana(chainId));
	const isSolanaEnabled = Boolean(enabled && isSolana(chainId));
	const { data: receipt } = useTransactionReceipt({
		hash: hash as Address,
		chainId,
		query: { enabled: isEvmEnabled },
	});

	const { rpcs } = useConfig();
	const { data: solanaTx, isLoading: solLoading } = useQuery({
		enabled: isSolanaEnabled,
		queryKey: ["solanaTx", hash],
		queryFn: async () => {
			if (!rpcs?.solana) {
				throw new Error("No Solana RPC provided");
			}
			const connection = new Connection(rpcs.solana);
			const tx = await connection.getParsedTransaction(hash, {
				maxSupportedTransactionVersion: 0,
			});
			return tx;
		},
	});

	const supportedTokens = useSupportedTokens({ input: true });

	// Token decimals & symbol should come from your supportedTokens config
	const chainTokens = supportedTokens?.[chainId];

	let value: bigint | undefined;
	let token: string | undefined;
	let transferIx: ParsedInstruction | undefined;

	// Refund tracking: existing logic
	const transferIxs = solanaTx?.transaction.message.instructions.filter(
		// biome-ignore lint/suspicious/noExplicitAny: <explanation>
		(ix: any) =>
			ix.program === "spl-token" &&
			(ix.parsed?.type === "transfer" || ix.parsed?.type === "transferChecked"),
	) as ParsedInstruction[] | undefined;

	transferIx =
		transferIxs?.find(
			(ix) =>
				ix.parsed?.info?.mint?.toLowerCase() ===
				targetTokenAddress?.toLowerCase(),
		) || transferIxs?.[0];

	const logs = receipt?.logs?.filter((log) => {
		return (
			[...signatures.map((sig) => sig.toLowerCase())].includes(
				log.topics[0] as string,
			) &&
			(targetTokenAddress
				? log.address?.toLowerCase() === targetTokenAddress?.toLowerCase()
				: true)
		);
	});

	const log = targetTokenAddress ? logs?.[logs.length - 1] : logs?.[0];

	if (log?.topics?.[0]?.toLowerCase() === REQUEST_REFUNDED_SIG.toLowerCase()) {
		try {
			const [_requestHash, tokenAddr, amount, _refundTo] = decodeAbiParameters(
				parseAbiParameters("bytes32, address, uint256, address"),
				log.data as `0x${string}`,
			);

			value = amount;
			token = tokenAddr;
		} catch (e) {
			console.error("Failed to decode RequestRefunded log:", e);
		}
	} else {
		// fallback for ERC20 Transfer etc.
		value = BigInt(log?.data || "0");
		token = log?.address;
	}

	// Only fetch token info for refunds, not for same-chain swaps
	const refundTokenAddress = isSolana(chainId)
		? transferIx?.parsed?.info?.mint
		: token;

	const tokenInfo = chainTokens?.find(
		(t) => t.address.toLowerCase() === refundTokenAddress?.toLowerCase(),
	);

	const { data: apiTokenResult, isLoading: isSearchingTokens } = useSearch({
		keyword: refundTokenAddress || "",
		enabled: !targetTokenAddress && !tokenInfo, // Only for refunds
	});

	const refundToken =
		tokenInfo ||
		apiTokenResult?.find(
			(token) =>
				token.address.toLowerCase() === refundTokenAddress?.toLowerCase() &&
				token.chainId === chainId,
		);

	if (isSolana(chainId)) {
		if (solLoading || (isSearchingTokens && !targetTokenAddress))
			return { data: undefined, isLoading: true };
		if (!solanaTx || !transferIx) return { data: undefined, isLoading: false };

		// Parse token transfer
		const info = transferIx.parsed.info;
		const token = info.mint;

		return {
			data: {
				value: BigInt(info.tokenAmount.amount),
				token,
				chainId,
				decimals: info.tokenAmount.decimals,
				symbol: targetTokenAddress ? undefined : refundToken?.symbol,
				tokenInfo: targetTokenAddress ? undefined : refundToken,
			},
			isLoading: false,
		};
	}

	// EVM chains
	if (!value || !token) {
		return { data: undefined, isLoading: false };
	}

	// For same-chain swaps, don't require token info
	if (targetTokenAddress) {
		return {
			data: {
				value,
				token,
				chainId,
				decimals: undefined,
				symbol: undefined,
				tokenInfo: undefined,
			},
			isLoading: false,
		};
	}

	// For refunds, require token info
	if (!refundToken) {
		return { data: undefined, isLoading: false };
	}

	return {
		data: {
			value,
			token,
			chainId,
			decimals: refundToken.decimals,
			symbol: refundToken.symbol,
			tokenInfo: refundToken,
		},
		isLoading: false,
	};
};
