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

import { Button } from "@components/common/Button";
import type { AutoOrderData } from "@hooks/apis/auto/useAutoHistory";
import { useSubmit } from "@hooks/apis/auto/useSubmit";
import type { FormattedAutoQuote } from "@hooks/apis/common/quote/types";
import { useActiveRoute } from "@hooks/apis/common/quote/useActiveRoute";
import { useChainSwitcher } from "@hooks/useChainSwitcher";
import { useConfig } from "@hooks/useConfig";
import { useIsChainSwitchRequired } from "@hooks/useIsChainSwitchRequired";
import { USER_OPERATIONS, useLogError } from "@hooks/useLogError";
import { useToast } from "@providers/ToastProvider";
import { ScreenTab, setScreenTab } from "@store/globalSlice";
import { setInflightData } from "@store/inflightSlice";
import { setIsFetchingDisabled } from "@store/quoteParamSlice";
import { getCommonErrors } from "@utils/getCommonErrors";
import { useActionStatusContext } from "./ActionStatusProvider";

export type QueryStatus =
	| "awaiting_wallet_confirmation"
	| "loading"
	| "disabled"
	| "idle"
	| "error";

export const SignOrder = ({
	quoteData,
	disabled,
}: { quoteData: FormattedAutoQuote; disabled: boolean }) => {
	const dispatch = useDispatch();
	const { showToast } = useToast();
	const bungeeConfig = useConfig();
	const [signature, setSignature] = useState<string>("");
	const [status, setStatus] = useState<QueryStatus>("idle");
	const { switchToChain } = useChainSwitcher();
	const { isRefetching } = useActiveRoute();
	const { logError } = useLogError();

	const { signTypedData } = useSignTypedData();

	const { signTypedData: permit2Data, requestType, quoteId } = quoteData;

	const isChainSwitchRequired = useIsChainSwitchRequired({
		activeRoute: quoteData,
	});

	async function generateSignature() {
		try {
			dispatch(setIsFetchingDisabled(true));
			const chainSwitched = await switchToChain(quoteData.primaryInput.token.chainId);
			if (!chainSwitched) return;

			setStatus("awaiting_wallet_confirmation");
			if (permit2Data) {
				await signTypedData(
					{
						types: permit2Data.types,
						primaryType: "PermitWitnessTransferFrom",
						message: permit2Data.values,
						domain: permit2Data.domain,
					},
					{
						onSuccess: (data) => {
							setSignature(data);
						},
						onError: (data) => {
							setStatus("error");
							console.log("Error", data.message);
							const { shortMessage } = getCommonErrors(data);
							showToast("Signature Submission Failed", shortMessage, "error");
							bungeeConfig?.eventHandlers?.onEvent?.("error", {
								title: "Signature Submission Failed",
								message: shortMessage,
								action: "SIGN",
							});
							dispatch(setIsFetchingDisabled(false));
							logError(data.message, { operation: USER_OPERATIONS.SIGNATURE });
						},
					},
				);
			}
		} catch (err) {
			const _errTitle = "Signature Submission Failed";
			const _errMsg = "Please try again";

			showToast(_errTitle, _errMsg, "error");
			bungeeConfig?.eventHandlers?.onEvent?.("error", {
				title: _errTitle,
				message: _errMsg,
				action: "SIGN",
			});
			console.error(_errTitle, err);
			logError(err, {
				operation: USER_OPERATIONS.SIGNATURE,
				action: "signature-generation",
			});
		}
	}

	const { data, isLoading, isError } = useSubmit({
		signature,
		requestData: JSON.stringify({
			requestType: requestType,
			request: permit2Data?.values?.witness,
			userSignature: signature,
			quoteId,
		}),
	});

	useEffect(() => {
		if (isLoading) setStatus("loading");
		if (isError) setStatus("error");
	}, [isLoading, isError]);

	useEffect(() => {
		if (data) {
			/**
			 * To populate the inflight screen
			 */
			const inflightData: AutoOrderData = {
				...quoteData,
				output: quoteData.output.map((item) => ({
					...item,
					minAmountOut: quoteData.minOutput?.amount ?? "",
				})),
				primaryOutput: {
					...quoteData.output[0],
					minAmountOut: quoteData.minOutput?.amount ?? "",
				},
				statusCode: 0,
				status: "PENDING",
				swapTime: 0,
				srcTimestamp: 0,
				orderTimestamp: 0,
				flowType: "regular",
			};

			if (data) {
				dispatch(setIsFetchingDisabled(false)); // making sure quote is not disabled
				dispatch(
					setInflightData({
						data: inflightData,
					}),
				);
				dispatch(setScreenTab(ScreenTab.INFLIGHT));
			}
		} else {
			setStatus("error");
		}
	}, [data, dispatch, quoteData]);

	function getButtonLabel() {
		if (status === "awaiting_wallet_confirmation") return "Confirm in wallet";

		if (status === "loading") return "Submitting request";

		return "Swap";
	}

	function loadingState() {
		return (
			status === "awaiting_wallet_confirmation" || status === "loading" || isLoading
		);
	}

	const { setStatus: setActionStatus } = useActionStatusContext();
	useEffect(() => {
		setActionStatus(status);
	}, [status, setActionStatus]);

	return (
		<Button
			label={getButtonLabel()}
			onClick={generateSignature}
			disabled={disabled || !permit2Data || loadingState() || isRefetching}
			isLoading={loadingState()}
			id="sign-order-btn"
		/>
	);
};
