import { useEffect, useRef, useState } from "react";
import { useDispatch } from "react-redux";

import type { Token } from "@/types/index";
import {
	type QuoteParams,
	addOutputToken,
	setAmount,
	setFromChainId,
	setFromTokens,
	setToChainId,
} from "@store/quoteParamSlice";
import { parseValue } from "@utils/parseValue";
import { useConfig } from "./useConfig";
import { useSearch } from "./useSearch";
import { useSupportedChains } from "./useSupportedChains";
import { useSupportedTokens } from "./useSupportedTokens";

export const useSetInitialValues = () => {
	const config = useConfig();
	const dispatch = useDispatch();

	// Getting supported assets
	const supportedFromTokens = useSupportedTokens({ input: true });
	const supportedToTokens = useSupportedTokens({ input: false });
	const { supportedChains } = useSupportedChains({ input: true });
	const firstRender = useRef(true);

	// TO FETCH TOKENS WHEN NOT FOUND IN THE SHORTLIST
	const [shouldFetchTokens, setShouldFetchTokens] = useState<{
		src: boolean;
		dest: boolean;
	}>({ src: false, dest: false });

	const { data: fetchedSrcToken } = useSearch({
		keyword:
			(shouldFetchTokens.src && config.initialValues?.inputTokens?.[0]) || "",
	});

	const { data: fetchedDestToken } = useSearch({
		keyword:
			(shouldFetchTokens.dest && config.initialValues?.outputTokens?.[0]) || "",
	});

	useEffect(() => {
		if (fetchedSrcToken?.length) {
			setFetchedTokens(fetchedSrcToken[0], true);
		}
	}, [fetchedSrcToken]);

	useEffect(() => {
		if (fetchedDestToken?.length) {
			setFetchedTokens(fetchedDestToken[0], false);
		}
	}, [fetchedDestToken]);

	const setFetchedTokens = (token: Token, isSrc: boolean) => {
		if (isSrc) {
			dispatch(setFromTokens(token));
		} else {
			dispatch(addOutputToken({ id: 0, token }));
		}
	};
	// END

	const setChainId = (
		chainId: number | undefined,
		setChainIdAction: (chainId: number) => {
			type: string;
			payload: QuoteParams["fromChainId"];
		},
	) => {
		if (chainId) dispatch(setChainIdAction(chainId));
	};

	const setTokens = (
		chainId: number | undefined,
		tokenAddresses: string[] | undefined,
		supportedTokens: { [x: number]: Token[] },
		id?: number,
	) => {
		if (
			typeof chainId === "number" &&
			chainId !== 0 &&
			tokenAddresses?.every((addr) => Boolean(addr))
		) {
			const token = supportedTokens?.[chainId]?.find(
				(token) => token.address?.toLowerCase() === tokenAddresses[0].toLowerCase(),
			);

			if (token) {
				if (typeof id === "number") {
					dispatch(addOutputToken({ id, token })); // for output token
				} else {
					dispatch(setFromTokens(token));
				}
			} else {
				// Update combined state for fetching tokens
				setShouldFetchTokens({
					src: typeof id !== "number",
					dest: typeof id === "number",
				});
			}
		}
	};

	const dispatchAmount = (
		value: string,
		tokenAddress: string,
		supportedTokens: Token[],
	) => {
		if (!value) return;

		// Check if the value is a valid number string
		if (!/^\d+(\.\d+)?$/.test(value)) {
			console.error("Invalid amount format:", value);
			return; // Exit if the value is not valid
		}

		const activeToken = supportedTokens?.filter(
			(item) => item.address.toLowerCase() === tokenAddress.toLowerCase(),
		)?.[0];
		const parsedValue = parseValue(value, activeToken.decimals);
		if (parsedValue) dispatch(setAmount(parsedValue));
	};

	// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
	useEffect(() => {
		if (
			firstRender.current &&
			config?.apiKey &&
			supportedChains &&
			Object.keys(supportedFromTokens)?.length !== 0 &&
			Object.keys(supportedToTokens)?.length !== 0
		) {
			const { fromChain, toChain, inputTokens, outputTokens, amount } =
				config.initialValues || {};

			// SET INITIAL CHAINS
			setChainId(fromChain, setFromChainId);
			setChainId(toChain, setToChainId);

			// SET INITIAL TOKENS
			setTokens(fromChain, inputTokens, supportedFromTokens);
			setTokens(toChain, outputTokens, supportedToTokens, 0); // passing id for output token

			// SET AMOUNT
			const _inputToken = inputTokens?.[0];
			if (amount?.length && _inputToken && fromChain) {
				dispatchAmount(amount?.[0], _inputToken, supportedFromTokens?.[fromChain]);
			}

			firstRender.current = false;
		}
	}, [config, supportedFromTokens, supportedToTokens, supportedChains]);
};
