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

import {
	type FormattedQuoteResponse,
	ROUTE_TAG,
	type RouteTag,
} from "@hooks/apis/common/quote/types";
import { isManualQuote } from "@hooks/apis/common/quote/utils";
import type { ReduxStateType } from "@store/types";
import { adjustDecimals } from "@utils/adjustDecimals";
import { SLOW_ROUTE_THRESHOLD } from "@utils/constants";
import { formatValue } from "@utils/formatValue";
import { getTimeInMins } from "@utils/getTimeInMins";
import { twMerge } from "@utils/tailwindMerge";
import { DoubleChevron, SnailIcon } from "../Icons";
import { MIcon } from "../MIcon";
import { Fees } from "./utils/Fees";
import { RouteProtocol } from "./utils/RouteProtocol";

const typeColors = {
	SUGGESTED: {
		activeBg: "bn-bg-accent-1",
		bg: "bn-bg-layer-2",
		border: "bn-border-accent-1",
		text: "bn-text-accent-1",
	},
	FASTEST: {
		activeBg: "bn-bg-[#141424]",
		bg: "bn-bg-layer-2",
		border: "bn-border-accent-2",
		text: "bn-text-accent-2",
	},
	MAX_OUTPUT: {
		activeBg: "bn-bg-accent-3",
		bg: "bn-bg-layer-2",
		border: "bn-border-accent-3",
		text: "bn-text-accent-3",
	},
	DEFAULT: {
		activeBg: "bn-bg-layer-3",
		bg: "bn-bg-layer-2",
		border: "bn-border-transparent",
		text: "bn-text-secondary",
	},
	defaultActive: {
		activeBg: "bn-bg-[#241419]",
		bg: "bn-bg-layer-2",
		border: "bn-border-accent-pink",
		text: "bn-text-accent-pink",
	},
};

const getRouteLabel = (type: RouteTag | "DEFAULT") => {
	if (type === ROUTE_TAG.SUGGESTED) return "Suggested";
	if (type === ROUTE_TAG.FASTEST) return "Fastest";
	if (type === ROUTE_TAG.MAX_OUTPUT) return "Max output";
	return "";
};

const getRouteIcon = (type: RouteTag | "DEFAULT") => {
	if (type === ROUTE_TAG.SUGGESTED) {
		return (
			<div className="bn-size-fit -bn-rotate-90">
				<DoubleChevron fill="#FFD698" />
			</div>
		);
	}
	if (type === ROUTE_TAG.FASTEST)
		return <MIcon name="bolt" classNames="bn-text-lg" />;
	if (type === ROUTE_TAG.MAX_OUTPUT)
		return <MIcon name="attach_money" classNames="bn-text-xl" />;
	if (type === "DEFAULT")
		return (
			<div className="bn-size-fit bn-rotate-90 bn-flex bn-items-center bn-justify-center">
				<MIcon name="arrow_forward" classNames="bn-text-base" />
			</div>
		);
	return null;
};

type RouteItemType = {
	route: FormattedQuoteResponse;
	onClick: () => void;
	isActive: boolean;
	maxOutputRoute?: FormattedQuoteResponse;
	selectedRoute?: FormattedQuoteResponse;
	type: RouteTag | "DEFAULT";
	classNames?: string;
};

export const NewRouteItem = ({
	route,
	maxOutputRoute,
	selectedRoute,
	onClick,
	isActive,
	type,
	classNames,
}: RouteItemType) => {
	const [isHovered, setIsHovered] = useState(false);
	const locale = useSelector(
		(state: ReduxStateType) => state.settings.language,
	);
	const { primaryOutput, estimatedFulfilTime, isSwapRoute } = route;
	const isSlowRoute = estimatedFulfilTime >= SLOW_ROUTE_THRESHOLD;
	const toAmount = primaryOutput.amount;
	const toToken = primaryOutput.token;

	const routeOutputInUsd =
		route?.primaryOutput?.effectiveReceivedInUsd ||
		route?.primaryOutput?.valueInUsd;
	const maxOutputRouteOutputInUsd =
		maxOutputRoute?.primaryOutput?.effectiveReceivedInUsd ||
		maxOutputRoute?.primaryOutput?.valueInUsd;

	const priceDiff = useMemo(() => {
		if (routeOutputInUsd && maxOutputRouteOutputInUsd) {
			return maxOutputRouteOutputInUsd - routeOutputInUsd;
		}
		return 0;
	}, [routeOutputInUsd, maxOutputRouteOutputInUsd]);

	// Calculate price difference between selected route and current route for RouteTag types
	const selectedRouteOutputInUsd =
		selectedRoute?.primaryOutput?.effectiveReceivedInUsd ||
		selectedRoute?.primaryOutput?.valueInUsd;

	const selectedRoutePriceDiff = useMemo(() => {
		if (type === "DEFAULT" || isActive) {
			return 0;
		}

		if (!routeOutputInUsd || !selectedRouteOutputInUsd) {
			return 0;
		}

		if (route.quoteId === selectedRoute?.quoteId) {
			return 0;
		}

		return routeOutputInUsd - selectedRouteOutputInUsd;
	}, [
		type,
		isActive,
		routeOutputInUsd,
		selectedRouteOutputInUsd,
		route.quoteId,
		selectedRoute?.quoteId,
	]);

	// this price diff label is used for the DEFAULT type, the above selectedRoutePriceDiff is used for the RouteTag types
	const priceDiffLabel = (isHovered = false) => {
		// priceDiff is positive when selected route gives less than max output (showing loss)
		// priceDiff is negative when selected route gives more than max output (showing gain)
		const absPriceDiff = Math.abs(priceDiff);
		const sign = priceDiff > 0 ? "-" : "+";

		return (
			<span
				className={`bn-text-sm bn-font-medium ${isHovered ? "bn-text-accent-pink" : "bn-text-primary"}`}
			>
				{sign}${adjustDecimals({ value: absPriceDiff, decimals: 2, locale })} vs{" "}
				MAX OUTPUT
			</span>
		);
	};

	// returns either auto tag or manual route icons
	const routeType = () => {
		if (isManualQuote(route)) {
			return <RouteProtocol routeDetails={route.protocol} />;
		}

		return null;
	};

	const getRouteColors = () => {
		// Use defaultActive colors when type is "DEFAULT" and item is active
		const colors =
			type === "DEFAULT" && isActive
				? typeColors.defaultActive
				: typeColors[type];
		return {
			background: isActive ? colors.activeBg : colors.bg,
			border: isActive ? colors.border : "bn-border-transparent",
			text: isActive ? "bn-text-primary" : "bn-text-secondary",
		};
	};

	const routeColors = getRouteColors();
	const hoverClasses = isActive
		? ""
		: "hover:bn-text-primary group hover:bn-bg-layer-3";
	const style = twMerge(
		`${routeColors.background} ${routeColors.border} ${routeColors.text} bn-rounded-lg bn-flex bn-justify-between bn-border bn-border-solid bn-px-3 bn-py-2.5 bn-flex-1 bn-cursor-pointer bn-w-full ${hoverClasses}`,
		classNames,
	);

	const estimatedFulfilTimeLabel =
		isManualQuote(route) && isSwapRoute
			? "10s"
			: estimatedFulfilTime
				? getTimeInMins(estimatedFulfilTime).compactTime
				: null;

	return (
		<button
			type="button"
			className={style}
			onClick={onClick}
			onMouseEnter={() => !isActive && setIsHovered(true)}
			onMouseLeave={() => !isActive && setIsHovered(false)}
		>
			<div className="bn-flex bn-items-center bn-space-x-2.5">
				<RouteIcon
					type={type}
					isHovered={!isActive && isHovered}
					isActive={isActive}
				/>
				<div className="bn-flex bn-space-y-1 bn-flex-col bn-items-start">
					<div
						className={`bn-flex bn-items-center bn-space-x-2 bn-text-sm bn-font-semibold bn-leading-[17px] bn-uppercase ${type === "DEFAULT" && isActive ? typeColors.defaultActive.text : typeColors[type].text}`}
					>
						<span className="bn-whitespace-nowrap">
							{type === "DEFAULT"
								? priceDiffLabel(isHovered || isActive)
								: getRouteLabel(type)}
						</span>
						{isActive && (
							<MIcon
								name="check_circle"
								classNames={`bn-text-base bn-ml-1 ${type === "DEFAULT" ? typeColors.defaultActive.text : typeColors[type].text}`}
							/>
						)}
						{selectedRoutePriceDiff !== 0 && (
							<PriceDiffLabel priceDiff={selectedRoutePriceDiff} />
						)}
					</div>
					<div className="bn-flex bn-items-center bn-justify-center bn-space-x-2 bn-aeonik-font bn-text-[15px] bn-font-medium bn-leading-5 bn-tracking-[1%]">
						<div className="bn-text-left">
							{adjustDecimals({
								value: formatValue(toAmount, toToken.decimals),
								decimals: 3,
								locale,
							})}{" "}
							{toToken.symbol}
						</div>
						{estimatedFulfilTimeLabel && (
							<>
								<Divider />
								<div className="bn-flex bn-items-center bn-space-x-1">
									{isSlowRoute ? <SnailIcon /> : null}
									<span>{estimatedFulfilTimeLabel}</span>
								</div>
							</>
						)}
					</div>
				</div>
			</div>

			<div className="bn-flex bn-flex-col bn-items-end bn-justify-end bn-space-y-2">
				{routeType()}
				<Fees route={route} />
			</div>
		</button>
	);
};

const Divider = () => {
	return (
		<div className="bn-w-[1px] bn-h-[10px] bn-bg-[#373A3E] bn-rounded-full bn-shrink-0" />
	);
};

const RouteIcon = ({
	type,
	isHovered,
	isActive,
}: {
	type: RouteTag | "DEFAULT";
	isHovered?: boolean;
	isActive?: boolean;
}) => {
	// Use defaultActive colors when type is "DEFAULT" and item is active
	const colors =
		type === "DEFAULT" && isActive
			? typeColors.defaultActive
			: typeColors[type];
	const style = twMerge(
		"bn-size-8 bn-rounded-full bn-border-solid bn-border bn-flex bn-items-center bn-justify-center",
		colors.text,
		colors.border,
		type === "DEFAULT"
			? isHovered
				? "bn-bg-border-strong"
				: "bn-bg-border-subtle"
			: colors.activeBg,
	);

	return <div className={style}>{getRouteIcon(type)}</div>;
};

const PriceDiffLabel = ({ priceDiff }: { priceDiff: number }) => {
	const locale = useSelector(
		(state: ReduxStateType) => state.settings.language,
	);
	return (
		<span
			className={`bn-text-xs bn-font-medium bn-whitespace-nowrap bn-aeonik-font bn-px-1.5 bn-py-0.5 bn-rounded-full ${priceDiff > 0 ? "bn-bg-accent-3 bn-text-accent-3" : "bn-bg-accent-4 bn-text-accent-4"}`}
		>
			{priceDiff > 0 ? "+" : "-"}$
			{adjustDecimals({
				value: Math.abs(priceDiff),
				decimals: 2,
				locale,
			})}{" "}
			vs Selected
		</span>
	);
};
