import { useModalsManagerContext } from "@/contexts/ModalsManagerContext";
import type { IpaymentStackNavigator } from "@/navigations/Types";
import {
	type IorangePaymentStarter,
	getTransactionStatus,
	getTransactionsData,
} from "@/utils/requests/orangePayment";
import ErrorModal from "@components/modals/ErrorModal";
import LoadingModal from "@components/modals/LoadingModal";
import { LOG } from "@logger";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { AxiosError } from "axios";
import * as WebBrowser from "expo-web-browser";
import { useRef, useState } from "react";

import { AppState, Platform } from "react-native";

const log = LOG.extend("useOrangeMoney");

const paymentObjectDefault: IorangePaymentStarter = {
	// biome-ignore lint/style/useNamingConvention: <api expect type_paiement>
	type_paiement: 1,
	marchand: "1",
	service: "2",
	montant: 0,
	numero: "0707070707",
	commentaire: "Un commentaire",
};
const useOrangeMoney = (
	navigation?: NativeStackNavigationProp<
		IpaymentStackNavigator,
		"paymentAmountInputScreen",
		"IpaymentStackNavigator"
	>,
) => {
	const queryClient = useQueryClient();

	const [isBrowserOpen, setIsBrowserOpen] = useState(false);
	const { showModal, closeModal } = useModalsManagerContext();
	const appState = useRef(AppState.currentState);
	const [appStateVisible, setAppStateVisible] = useState(appState.current);

	const handlePaymentUsingBrowser = async (url: string) => {
		setIsBrowserOpen(true);
		const result = await WebBrowser.openBrowserAsync(url);
		// setResult(result);
		log.debug("handlePaymentUsingBrowser | Result ::", result);
		setIsBrowserOpen(false);
	};

	const orangeTransactionInitializerMutation = useMutation({
		mutationFn: (amount: number) =>
			getTransactionsData({
				...paymentObjectDefault,
				montant: amount,
			}),
		onSuccess: (data) => {
			// return data.payment_url
			log.debug("orangeTransactionInitializerMutation request success, opening browser...");
			queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] });
			// await handlePaymentUsingBrowser(data.payment_url);
			// await transactionsStatusMutation.mutate(data.order_id);
			// setResult(result);
		},
		onError: (err) => {
			log.error("orangeTransactionInitializerMutation |", err);
		},
	});

	const maxRetry = 3;
	const retryDelay = 5000;

	const transactionsStatusMutation = useMutation({
		mutationFn: (orderId: string) => getTransactionStatus(orderId),
		onSuccess: (data) => {
			log.debug("transactionsStatusMutation request success");
			queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] });
			return data.status;
		},
		onError: (err) => {
			log.error("transactionsStatusMutation |", err);
			queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] });
		},
		// retry: (failureCount, error) => {
		// 	log.warn("transactionsStatusMutation | retrying", failureCount, error);
		// 	return failureCount < maxRetry;
		// },
		// retryDelay(_failureCount, _error) {
		// 	return retryDelay;
		// },
	});

	// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <Necessarry evil>
	const checkStatus = async (orderId: string, retry = 0): Promise<string | undefined> => {
		// Check the transactions 'retry' time.
		let numberOfTries = 0;

		while (numberOfTries <= retry) {
			log.verbose("useOrangePayment | checkStatus | Try No.", numberOfTries + 1);
			try {
				await transactionsStatusMutation.mutateAsync(orderId);
				return;
			} catch (error) {
				// errors are throwned from getTransactions status when the staus is either initiated or failed.
				if (error instanceof AxiosError && error.response?.status === 404) {
					log.error("useOrangeMoney | checkStatus | Transaction not found");
					return error.response.data.error || `Transaction ${orderId} not found !!`;
				}
				if (error instanceof AxiosError && error.name === "ORANGE_PAYMENT_FAILED") {
					return "La transaction à échoué.";
				}
				if (error instanceof AxiosError && error.name === "ORANGE_UNKNOWN_PAYMENT_ERROR") {
					return "Une erreur est survenue.";
				}
			}

			numberOfTries += 1;
		}

		return "La transaction est toujours en cours.";
	};

	const openBrowserThenCheckStatus = async (paymentUrl: string, orderId: string) => {
		try {
			await handlePaymentUsingBrowser(paymentUrl);
			if (Platform.OS === "android") {
				log.debug(
					"useOrangeMoney | openBrowserThenCheckStatus | Android device. Setup listener for browser close event.",
				);
				const sub = AppState.addEventListener("change", async (nextAppState) => {
					log.debug(
						"useOrangeMoney | openBrowserThenCheckStatus | Android device. Browser state :",
						nextAppState,
					);

					if (nextAppState === "active") {
						log.debug(
							"useOrangeMoney | openBrowserThenCheckStatus | Android device. Browser is closed. Removing listener. Checking for transaction State.",
						);
						sub.remove();
						log.info("openBrowserThenCheckStatus | Verifying transaction status...");
						showModal(
							<LoadingModal message="Vérification du statut de la transaction..." />,
						);
						// await transactionsStatusMutation.mutateAsync(orderId);
						const message = await checkStatus(orderId);
						if (message) {
							showModal(<ErrorModal message={message} />);
						} else {
							navigation?.getParent()?.navigate("paymentResultScreen");
						}
					}
				});
			} else {
				log.info("openBrowserThenCheckStatus | Verifying transaction status...");
				showModal(<LoadingModal message="Vérification du statut de la transaction..." />);
				// await transactionsStatusMutation.mutateAsync(orderId);
				const message = await checkStatus(orderId);
				if (message) {
					showModal(<ErrorModal message={message} />);
				} else {
					navigation?.getParent()?.navigate("paymentResultScreen");
				}
			}
			// closeModal();
		} catch (error: unknown) {
			log.verbose("Error catching");
			if (error instanceof AxiosError) {
				log.error("openBrowserThenCheckStatus Catch Block|", error);
				showModal(
					<ErrorModal
						message={error.response?.data.error || "Une erreur Axios est survenue."}
					/>,
				);
			} else {
				showModal(<ErrorModal message="Une erreur est survenue." />);
			}
			// log.error("openBrowserThenCheckStatus Catch Block|", error);
			// if (error instanceof Error) {
			// 	log.debug("1");
			// 	if (error.name === "ORANGE_PAYMENT_IN_PROGRESS") {
			// 		log.debug("2");

			// 		log.warn("openBrowserThenCheckStatus | ORANGE_PAYMENT_IN_PROGRESS");
			// 		await showModal(
			// 			<InformationModal
			// 				message="Le payment est toujours en cours."
			// 				actionLabel="Rééssayer"
			// 				onPress={() => openBrowserThenCheckStatus(paymentUrl, orderId)}
			// 			/>,
			// 		);
			// 		log.debug("3");
			// 	} else if (error.name === "ORANGE_PAYMENT_FAILED") {
			// 		showModal(<ErrorModal message="Le paiment à échoué." />);
			// 		log.error("openBrowserThenCheckStatus | ORANGE_PAYMENT_FAILED");
			// 	}
			// 	log.debug("4 --", error.name);
			// } else {
			// 	log.error("openBrowserThenCheckStatus Else Block|", error);
			// 	closeModal();
			// 	throw error;
			// }
		}
	};

	const orangePaymentTransactionHandler = async (amount: number) => {
		try {
			showModal(<LoadingModal message="Initialization de la transaction." />);
			const { payment_url, order_id } =
				await orangeTransactionInitializerMutation.mutateAsync(amount);
			log.info("orangePaymentTransactionHandler |", payment_url, order_id);
			log.info("Opening browser for payment...");
			await openBrowserThenCheckStatus(payment_url, order_id);
			// biome-ignore lint/suspicious/noExplicitAny: <TODO: Change this later>
		} catch (error: any) {
			log.error("makePayment |", error);
			showModal(
				<ErrorModal message={error.response?.data?.error || "Une erreur est survenue."} />,
			);

			throw error;
		} finally {
			//closeModal(); // just to be ultra sure that the modal is closed
		}
	};

	return {
		orangeTransactionInitializerMutation: orangeTransactionInitializerMutation,

		handlePaymentUsingBrowser,
		isBrowserOpen,
		isWaitingForOmPaymentUrl: orangeTransactionInitializerMutation.isPending,
		isCheckingForTransactionStatus: transactionsStatusMutation.isPending,
		transactionsStatusMutation,
		orangePaymentTransactionHandler,
	};
};

export default useOrangeMoney;
