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

import { useTopRoutes } from "@hooks/apis/common/quote/useTopRoutes";
import { setOriginalRoutingMode, setRoutingMode } from "@store/settingsSlice";
import type { ReduxStateType } from "@store/types";

/**
 * Hook to detect and manage temporary routing mode switches.
 * Returns whether routing mode is temporarily switched and to which mode.
 * Also handles auto-switching logic when routes are not available for current mode.
 */
export const useTemporaryRoutingMode = () => {
	const dispatch = useDispatch();
	const routingMode = useSelector(
		(state: ReduxStateType) => state.settings.routingMode,
	);
	const originalRoutingMode = useSelector(
		(state: ReduxStateType) => state.settings.originalRoutingMode,
	);
	const { auto, manual, formattedAutoRoutes, formattedManualRoutes } =
		useTopRoutes();

	const { isLoading: isQuotesLoading } = useSelector(
		(state: ReduxStateType) => state.routes,
	);

	// Track if we've already auto-switched to prevent infinite loops
	const hasAutoSwitchedRef = useRef(false);
	const lastRouteStateRef = useRef<string>("");
	// Track if we just switched modes to show notification
	const [justSwitched, setJustSwitched] = useState<"manual" | "auto" | null>(
		null,
	);
	// Track if we've already restored to prevent infinite loops
	const hasRestoredRef = useRef(false);

	// Determine route availability
	const autoRoutesAvailable = useMemo(() => {
		return !!(
			auto.suggestedRoute ||
			auto.maxOutputRoute ||
			auto.fastestRoute ||
			formattedAutoRoutes?.length
		);
	}, [
		auto.suggestedRoute,
		auto.maxOutputRoute,
		auto.fastestRoute,
		formattedAutoRoutes,
	]);

	const manualRoutesAvailable = useMemo(() => {
		return !!(
			manual.maxOutputRoute ||
			manual.fastestRoute ||
			formattedManualRoutes?.length
		);
	}, [manual.maxOutputRoute, manual.fastestRoute, formattedManualRoutes]);

	// Create a unique key for the current route state to detect changes (excluding routingMode to track route availability changes)
	const routeAvailabilityKey = useMemo(() => {
		return `${autoRoutesAvailable}-${manualRoutesAvailable}`;
	}, [autoRoutesAvailable, manualRoutesAvailable]);

	// Auto-switch modes when needed
	useEffect(() => {
		// Reset auto-switch flag when route availability changes (not when mode changes)
		if (routeAvailabilityKey !== lastRouteStateRef.current) {
			hasAutoSwitchedRef.current = false;
			hasRestoredRef.current = false;
			lastRouteStateRef.current = routeAvailabilityKey;
			// Clear justSwitched when route availability changes significantly
			// (e.g., both routes become available, or the opposite becomes available)
			if (
				(justSwitched === "manual" &&
					(autoRoutesAvailable || !manualRoutesAvailable)) ||
				(justSwitched === "auto" &&
					(manualRoutesAvailable || !autoRoutesAvailable))
			) {
				setJustSwitched(null);
			}
		}

		// Don't auto-switch if we already have an originalRoutingMode stored
		// (means we're already in a temporary switch state)
		if (originalRoutingMode) {
			return;
		}

		// Only auto-switch once per route availability change
		if (hasAutoSwitchedRef.current) return;

		// Auto mode selected, but only manual routes available
		if (
			routingMode === "auto" &&
			!autoRoutesAvailable &&
			manualRoutesAvailable
		) {
			dispatch(setOriginalRoutingMode("auto"));
			dispatch(setRoutingMode("manual"));
			hasAutoSwitchedRef.current = true;
			setJustSwitched("manual");
		}
		// Manual mode selected, but only auto routes available
		else if (
			routingMode === "manual" &&
			!manualRoutesAvailable &&
			autoRoutesAvailable
		) {
			dispatch(setOriginalRoutingMode("manual"));
			dispatch(setRoutingMode("auto"));
			hasAutoSwitchedRef.current = true;
			setJustSwitched("auto");
		}
	}, [
		routingMode,
		autoRoutesAvailable,
		manualRoutesAvailable,
		dispatch,
		routeAvailabilityKey,
		justSwitched,
		originalRoutingMode,
	]);

	// Auto-restore original mode when routes become available for it
	useEffect(() => {
		// Only restore if:
		// 1. We have a stored original mode in Redux
		// 2. Routes are now available for the original mode
		// 3. We haven't already restored for this route state
		// 4. Current mode doesn't match the original mode
		if (
			originalRoutingMode &&
			!hasRestoredRef.current &&
			routingMode !== originalRoutingMode
		) {
			// Check if routes are available for the original mode
			const originalModeRoutesAvailable =
				originalRoutingMode === "auto"
					? autoRoutesAvailable
					: manualRoutesAvailable;

			if (originalModeRoutesAvailable) {
				dispatch(setRoutingMode(originalRoutingMode));
				dispatch(setOriginalRoutingMode(null));
				hasRestoredRef.current = true;
				setJustSwitched(null);
			}
		}
	}, [
		originalRoutingMode,
		autoRoutesAvailable,
		manualRoutesAvailable,
		routingMode,
		dispatch,
	]);

	// Determine if routing mode is temporarily switched
	const isTemporarilySwitched = useMemo(() => {
		// Show as temporarily switched if:
		// 1. We have an originalRoutingMode stored in Redux (persists across navigation)
		// 2. Current routingMode doesn't match the original mode
		// 3. Routes are not available for the original mode (still need temporary switch)
		// OR during loading, preserve state if originalRoutingMode exists and modes don't match
		if (!originalRoutingMode) {
			return false;
		}

		// During loading, preserve the temporary switch state if modes don't match
		if (isQuotesLoading && routingMode !== originalRoutingMode) {
			return true;
		}

		if (
			originalRoutingMode === "auto" &&
			routingMode === "manual" &&
			!autoRoutesAvailable &&
			manualRoutesAvailable
		) {
			return true;
		}
		if (
			originalRoutingMode === "manual" &&
			routingMode === "auto" &&
			!manualRoutesAvailable &&
			autoRoutesAvailable
		) {
			return true;
		}
		return false;
	}, [
		originalRoutingMode,
		routingMode,
		autoRoutesAvailable,
		manualRoutesAvailable,
		isQuotesLoading,
	]);

	return {
		isTemporarilySwitched,
		switchedToMode: isTemporarilySwitched
			? originalRoutingMode === "auto"
				? "manual"
				: "auto"
			: null,
		originalMode: originalRoutingMode,
	};
};
