import { getAccountCurrency, getFeesUnit } from "@ledgerhq/coin-framework/account/index";
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
import { AmountRequired, FeeNotLoaded, NotEnoughBalanceSwap, NotEnoughGas, NotEnoughGasSwap, } from "@ledgerhq/errors";
import { useEffect, useMemo, useState } from "react";
import useBridgeTransaction from "../../../bridge/useBridgeTransaction";
import { useFromState } from "./useFromState";
import { useReverseAccounts } from "./useReverseAccounts";
import { useToState } from "./useToState";
import { useUpdateMaxAmount } from "./useUpdateMaxAmount";
import { useProviderRates } from "./v5/useProviderRates";
export const selectorStateDefaultValues = {
    currency: undefined,
    account: undefined,
    parentAccount: undefined,
    amount: undefined,
};
export const useFromAmountStatusMessage = ({ account, parentAccount, status, transaction }, 
// The order of errors/warnings here will determine the precedence
statusTypeToInclude, sponsored) => {
    const statusEntries = useMemo(() => statusTypeToInclude.map(statusType => (status.errors || status.warnings)?.[statusType]), [status.errors, status.warnings, statusTypeToInclude]);
    const currency = useMemo(() => {
        if (parentAccount) {
            return getAccountCurrency(parentAccount);
        }
        if (account) {
            return getAccountCurrency(account);
        }
        return undefined;
    }, [account, parentAccount]);
    const estimatedFees = useMemo(() => {
        return status.estimatedFees;
    }, [status]);
    return useMemo(() => {
        // don't return an error/warning if we have no transaction or if transaction.amount <= 0
        if (transaction?.amount.lte(0))
            return undefined;
        const [relevantStatus] = statusEntries
            .filter(maybeError => maybeError instanceof Error)
            .filter(errorOrWarning => !(errorOrWarning instanceof AmountRequired));
        const isRelevantStatus = relevantStatus instanceof NotEnoughGas;
        // Skip gas validation for sponsored transactions since gas fees are covered by sponsor
        if (isRelevantStatus && currency && estimatedFees && !sponsored) {
            const query = new URLSearchParams({
                // get account id first and set it equal to account.
                // if parent account exists then overwrite the former.
                ...(account?.id ? { account: account.id } : {}),
                ...(parentAccount?.id ? { account: parentAccount.id } : {}),
            });
            return new NotEnoughGasSwap(undefined, {
                fees: formatCurrencyUnit(getFeesUnit(currency), estimatedFees),
                ticker: currency.ticker,
                cryptoName: currency.name,
                links: [`ledgerlive://buy?${query.toString()}`],
            });
        }
        // convert to swap variation of error to display correct message to frontend.
        if (relevantStatus instanceof FeeNotLoaded) {
            return new NotEnoughBalanceSwap();
        }
        return relevantStatus;
    }, [
        statusEntries,
        currency,
        estimatedFees,
        transaction?.amount,
        account?.id,
        parentAccount?.id,
        sponsored,
    ]);
};
export const useSwapTransaction = ({ accounts, setExchangeRate, defaultCurrency = selectorStateDefaultValues.currency, defaultAccount = selectorStateDefaultValues.account, defaultParentAccount = selectorStateDefaultValues.parentAccount, onNoRates, excludeFixedRates, refreshRate, allowRefresh, isEnabled, sponsored, }) => {
    const bridgeTransaction = useBridgeTransaction(() => ({
        account: defaultAccount,
        parentAccount: defaultParentAccount,
    }));
    const { fromState, setFromAccount, setFromAmount } = useFromState({
        accounts,
        defaultCurrency,
        defaultAccount,
        defaultParentAccount,
        bridgeTransaction,
    });
    const { toState, setToAccount, setToAmount, setToCurrency, targetAccounts } = useToState({
        accounts,
        fromCurrencyAccount: fromState.account,
    });
    const { account: fromAccount, parentAccount: fromParentAccount, currency: fromCurrency, } = fromState;
    const { account: toAccount } = toState;
    const fromAmountError = useFromAmountStatusMessage(bridgeTransaction, ["gasPrice", "amount", "gasLimit"], sponsored);
    const { isSwapReversable, reverseSwap } = useReverseAccounts({
        accounts,
        fromAccount,
        toAccount,
        fromParentAccount,
        fromCurrency,
        setFromAccount,
        setToAccount,
    });
    const { isMaxEnabled, toggleMax, isMaxLoading } = useUpdateMaxAmount({
        setFromAmount,
        account: fromAccount,
        parentAccount: fromParentAccount,
        bridge: bridgeTransaction,
    });
    const { rates, refetchRates, updateSelectedRate, countdown } = useProviderRates({
        fromState,
        toState,
        onNoRates,
        setExchangeRate,
        countdown: refreshRate,
        allowRefresh,
        isEnabled,
    });
    const [maxAmountLowerThanBallanceError, setMaxAmountLowerThanBallanceError] = useState(undefined);
    useEffect(() => {
        const timer = setTimeout(() => {
            // libs/coin-modules/coin-evm/src/prepareTransaction.ts L47
            // returns 0 if the balance - fees is less than 0
            const error = isMaxEnabled && !isMaxLoading && fromState.amount?.eq(0)
                ? new NotEnoughBalanceSwap()
                : undefined;
            setMaxAmountLowerThanBallanceError(error);
        }, isMaxEnabled ? 500 : 0);
        // Cleanup the timeout if the component unmounts or the dependencies change
        return () => clearTimeout(timer);
    }, [isMaxEnabled, isMaxLoading, fromState]);
    return {
        ...bridgeTransaction,
        swap: {
            to: toState,
            from: fromState,
            isMaxEnabled,
            isMaxLoading,
            isSwapReversable,
            rates: rates.value && excludeFixedRates
                ? {
                    ...rates,
                    value: rates.value.filter(v => v.tradeMethod !== "fixed"),
                }
                : rates,
            countdown,
            refetchRates,
            updateSelectedRate,
            targetAccounts,
        },
        setFromAmount,
        toggleMax,
        fromAmountError: maxAmountLowerThanBallanceError || fromAmountError,
        setToAccount,
        setToCurrency,
        setFromAccount,
        setToAmount,
        reverseSwap,
    };
};
//# sourceMappingURL=useSwapTransaction.js.map