import { useEffect, useMemo, useState } from "react";

import type { Token } from "@/types/index";
import { useSupportedChains } from "@hooks/useSupportedChains";
import type { Chain } from "@store/globalSlice";

/**
 * useSearchTokens.ts
 *
 * A custom React hook used for token and network search functionality.
 *
 * Key Features:
 * - Searches a short list of tokens based on user input.
 * - Supports searching by token name, symbol, or address.
 * - Allows optional filtering by network name (if provided in search).
 * - Prioritizes results from the active network and sorts by USD balance.
 * - Returns both matching tokens and matching networks.
 *
 * @returns An object containing:
 *   - `tokenResult`: A filtered and sorted list of tokens matching the search.
 *   - `networkResult`: A list of networks matching the search query.
 */
export const useSearchTokens = ({
	searchValue,
	tokens,
	activeNetwork,
}: { searchValue: string; tokens: Token[]; activeNetwork?: number }) => {
	const { supportedChains } = useSupportedChains({ input: true });

	const { mappedChains, chainNames } = useMemo(() => {
		const chains: Record<string, number> = {};

		for (const chain of supportedChains) {
			chains[chain.name.toLowerCase()] = chain.chainId;
		}
		return {
			mappedChains: chains,
			chainNames: Object.keys(chains),
		};
	}, [supportedChains]);

	const searchBreakdown = useMemo(() => {
		return searchValue
			?.trim()
			.split(" ")
			.filter((keyword) => keyword); // Remove empty strings
	}, [searchValue]);

	const searchValueLowerCased = useMemo(() => {
		return searchBreakdown?.[0]?.toLowerCase();
	}, [searchBreakdown]);

	const searchedTokens = useMemo(() => {
		if (!tokens || !searchValueLowerCased) return;

		const filteredTokens = tokens?.filter(
			(token: Token) =>
				token?.symbol?.toLowerCase()?.includes(searchValueLowerCased) ||
				token?.address?.toLowerCase()?.includes(searchValueLowerCased) ||
				token?.name?.toLowerCase()?.includes(searchValueLowerCased),
		);

		// Sort tokens first by activeNetwork, then by balanceInUsd
		// to reverse the sort order, move the activeNetwork sorting below
		return filteredTokens?.sort((a: Token, b: Token) => {
			// Prioritize tokens by activeNetwork
			if (a.chainId === activeNetwork && b.chainId !== activeNetwork) return -1;
			if (a.chainId !== activeNetwork && b.chainId === activeNetwork) return 1;

			// Now sort by balanceInUsd
			if (a.balanceInUsd && !b.balanceInUsd) return -1;
			if (!a.balanceInUsd && b.balanceInUsd) return 1;
			if (a.balanceInUsd && b.balanceInUsd && a.balanceInUsd !== b.balanceInUsd) {
				return b.balanceInUsd - a.balanceInUsd; // Sort by balanceInUsd descending
			}
			return 0; // Maintain original order for other tokens
		});
	}, [tokens, searchValueLowerCased, activeNetwork]);

	const [results, setResults] = useState<{
		tokenResult: Token[];
		networkResult: Chain[];
	}>({
		tokenResult: [],
		networkResult: [],
	});

	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if (!searchedTokens) return;

		let tokenResult = searchedTokens;

		// If 2nd value is passed, assuming that is token name
		// Filtering tokens based on chain identified
		if (searchBreakdown?.length > 1) {
			const chainKeyword = searchBreakdown[1];
			const chainIdentified = chainNames.filter((chainName) =>
				chainName.toLowerCase().includes(chainKeyword.toLowerCase()),
			)?.[0];
			const chainId = mappedChains?.[chainIdentified];

			if (chainId !== undefined) {
				tokenResult = [...searchedTokens]?.filter(
					(token: Token) => token.chainId === chainId,
				);
			}
		}

		const networkResult = supportedChains?.filter((chain) => {
			// Not optimized for more than 2 search keywords
			if (searchBreakdown?.length > 2) return;

			const chainNameLc = chain.name.toLowerCase();
			return (
				chainNameLc.includes(searchBreakdown?.[0].toLowerCase()) ||
				chainNameLc.includes(searchBreakdown?.[1]?.toLowerCase())
			);
		});

		setResults({ tokenResult, networkResult });
	}, [searchedTokens, searchValue]);

	return results;
};
