import { calculateRates } from "@utils/calculateRates";
import { formatValue } from "@utils/formatValue";
import { getAutoMinOutput, getManualMinOutput } from "@utils/getMinOutput";
import type {
	BungeeQuote,
	FormattedAutoQuote,
	FormattedManualQuote,
	FormattedQuoteResponse,
} from "./types";

export function formatAutoRoute(
	data: BungeeQuote,
	autoRoute?: BungeeQuote["autoRoute"],
): FormattedAutoQuote | undefined {
	const route = autoRoute ?? data?.autoRoute;
	if (!route) return;

	const { input } = data;
	const output = route.output;

	const minOutput = getAutoMinOutput(output, route.slippage);

	// deriving formatted amounts to calculate the exchange rate
	const formattedInputAmount = input
		? formatValue(input.amount, input.token.decimals)
		: "0";
	const formattedOutputAmount = output
		? formatValue(output.amount, output.token.decimals)
		: "0";

	const { srcToDestRate, destToSrcRate } = calculateRates(
		formattedInputAmount,
		formattedOutputAmount,
	);

	return {
		...route,
		requestType: route.requestType,
		routingMode: "auto",
		receiver: data.receiverAddress,
		sender: data.userAddress,
		input: [data.input],
		output: [route.output],
		primaryInput: data.input,
		primaryOutput: route.output,
		estimatedFulfilTime: route.estimatedTime,
		// derived
		isSwapRoute: route.requestType === "SWAP_REQUEST",
		slippage: route.slippage,
		minOutput,
		srcToDestRate,
		destToSrcRate,
		rewards: route?.rewards?.isRewardEnabled ? route.rewards : undefined,
	};
}

export function formatAutoRoutes(
	data: BungeeQuote,
): FormattedAutoQuote[] | undefined {
	const autoRoutes = data?.autoRoutes;
	if (!autoRoutes?.length) return;

	return autoRoutes
		.map((autoRoute) => formatAutoRoute(data, autoRoute))
		.filter((route): route is FormattedAutoQuote => route !== undefined);
}

export function formatManualRoutes(
	data: BungeeQuote,
): FormattedManualQuote[] | undefined {
	const manualRoutes = data?.manualRoutes;
	if (!manualRoutes?.length) return;

	return manualRoutes.map((item): FormattedManualQuote => {
		const minOutput = getManualMinOutput(item.output);

		// deriving formatted amount to calculate exchange rate
		const formattedInputAmount =
			data.input && formatValue(data.input.amount, data.input.token.decimals);
		const formattedOutputAmount =
			item.output &&
			formatValue(item.output.amount, item.output.token.decimals);

		const { srcToDestRate, destToSrcRate } = calculateRates(
			formattedInputAmount,
			formattedOutputAmount,
		);

		return {
			...item,
			receiver: data.receiverAddress,
			sender: data.userAddress,
			input: [data.input],
			output: [item.output],
			primaryInput: data.input,
			primaryOutput: item.output,
			estimatedFulfilTime: item.estimatedTime,
			// derived
			isSwapRoute: item.output.token.chainId === data.input.token.chainId,
			// manual specific
			routingMode: "manual",
			protocol: item.routeDetails,
			totalGasFeesInUsd: item.gasFee.feeInUsd,
			receivedValueInUsd:
				item.output.valueInUsd && item.gasFee.feeInUsd
					? item.output.valueInUsd - item.gasFee.feeInUsd
					: 0,
			slippage: item?.slippage,
			minOutput,
			srcToDestRate,
			destToSrcRate,
			approvalData: item?.approvalData,
		};
	});
}

// Type guards for route types
export const isAutoQuote = (
	route: FormattedQuoteResponse | undefined | null,
): route is FormattedAutoQuote => route?.routingMode === "auto";

export const isManualQuote = (
	route: FormattedQuoteResponse | undefined | null,
): route is FormattedManualQuote => route?.routingMode === "manual";
