import { StyleSheet, View, TouchableOpacity, ScrollView } from 'react-native';
import {
  CENTER,
  CONTENT_KEYBOARD_OFFSET,
  QUICK_PAY_STORAGE_KEY,
  SATSPERBITCOIN,
  USDB_TOKEN_ID,
} from '../../../../constants';
import displayCorrectDenomination from '../../../../functions/displayCorrectDenomination';
import { useCallback, useEffect, useRef, useState, useMemo } from 'react';
import { useGlobalContextProvider } from '../../../../../context-store/context';
import {
  CustomKeyboardAvoidingView,
  GlobalThemeView,
  ThemeText,
} from '../../../../functions/CustomElements';
import SendTransactionFeeInfo from './components/feeInfo';
import usePaymentValidation from './functions/paymentValidation';
import decodeSendAddress from './functions/decodeSendAdress';
import { useNavigation } from '@react-navigation/native';
// import {useWebView} from '../../../../../context-store/webViewContext';
import GetThemeColors from '../../../../hooks/themeColors';
import CustomSearchInput from '../../../../functions/CustomElements/searchInput';
import FullLoadingScreen from '../../../../functions/CustomElements/loadingScreen';
import AcceptButtonSendPage from './components/acceptButton';
import NumberInputSendPage from './components/numberInput';
import FormattedBalanceInput from '../../../../functions/CustomElements/formattedBalanceInput';
import { useGlobalThemeContext } from '../../../../../context-store/theme';
import { useNodeContext } from '../../../../../context-store/nodeContext';
import ErrorWithPayment from './components/errorScreen';
import SwipeButtonNew from '../../../../functions/CustomElements/sliderButton';
import { crashlyticsLogReport } from '../../../../functions/crashlyticsLogs';
import {
  isSendingPayingEventEmiiter,
  SENDING_PAYMENT_EVENT_NAME,
  useSparkWallet,
} from '../../../../../context-store/sparkContext';
import { sparkPaymenWrapper } from '../../../../functions/spark/payments';
import InvoiceInfo from './components/invoiceInfo';
import formatSparkPaymentAddress from './functions/formatSparkPaymentAddress';
import ChoosePaymentMethod from './components/choosePaymentMethodContainer';
import ChooseLRC20TokenContainer from './components/chooseLRC20TokenContainer';
import { useActiveCustodyAccount } from '../../../../../context-store/activeAccount';
import { useTranslation } from 'react-i18next';
import {
  COLORS,
  HIDDEN_OPACITY,
  INSET_WINDOW_WIDTH,
  SIZES,
  WINDOWWIDTH,
} from '../../../../constants/theme';
import { SliderProgressAnimation } from '../../../../functions/CustomElements/sendPaymentAnimation';
import { InputTypes } from 'bitcoin-address-parser';
import CustomSettingsTopBar from '../../../../functions/CustomElements/settingsTopBar';
import { useWebView } from '../../../../../context-store/webViewContext';
import { useGlobalInsets } from '../../../../../context-store/insetsProvider';
import EmojiQuickBar from '../../../../functions/CustomElements/emojiBar';
import { useGlobalContactsInfo } from '../../../../../context-store/globalContacts';
import { bulkUpdateSparkTransactions } from '../../../../functions/spark/transactions';
import { useKeysContext } from '../../../../../context-store/keys';
import { useUserBalanceContext } from '../../../../../context-store/userBalanceContext';
import CustomButton from '../../../../functions/CustomElements/button';
import { useFlashnet } from '../../../../../context-store/flashnetContext';
import SwapRatesChangedState from './components/swapRatesChangedState';
import {
  dollarsToSats,
  satsToDollars,
  getLightningPaymentQuote,
  USD_ASSET_ADDRESS,
} from '../../../../functions/spark/flashnet';
import useCurrencyDisplay from '../../../../hooks/useCurrencyDisplay';
import useDisplayCurrencyController from '../../../../hooks/useDisplayCurrencyController';
import normalizeLNURLAddress from '../../../../functions/lnurl/normalizeLNURLAddress';
import { publishMessage } from '../../../../functions/messaging/publishMessage';
import { useToast } from '../../../../../context-store/toastManager';
import useDebounce from '../../../../hooks/useDebounce';
import customUUID from '../../../../functions/customUUID';
import { useBudgetWarning } from '../../../../hooks/useBudgetWarning';
import { getLNAddressForLiquidPayment } from './functions/payments';
import formatTokensNumber from '../../../../functions/lrc20/formatTokensBalance';
import {
  getDefaultDisplayCurrency,
  resolveUsdFiatStats,
} from '../../../../functions/displayCurrency';
import CurrencySwitchButton from '../../../../functions/CustomElements/currencySwitchButton';
import SecondaryAmountDisplay from './components/secondaryAmountDisplay';
import { lnurlCurrencyToRate } from '../../../../functions/sendBitcoin/lnurlCurrencyRate';
import { PROVIDER_COUNTRY_CURRENCY } from '../../../../functions/sendBitcoin/getPhonePaymentAddress';
import { fiatCurrencies } from '../../../../functions/currencyOptions';

export default function SendPaymentScreen(props) {
  console.log('CONFIRM SEND PAYMENT SCREEN');
  const navigate = useNavigation();
  const {
    btcAdress,
    fromPage,
    publishMessageFunc,
    comingFromAccept,
    enteredPaymentInfo = {},
    errorMessage,
    contactInfo,
    masterTokenInfo = {},
    selectedPaymentMethod = '',
    preSelectedPaymentMethod,
    selectedContact,
    retrivedContact,
    paymentDisplayCurrency,
    paymentDisplayFiatStats,
  } = props.route.params;

  const paramsRef = useRef({
    btcAdress,
  });

  const { poolInfoRef, swapLimits, swapUSDPriceDollars } = useFlashnet();
  const { t } = useTranslation();
  const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
    useUserBalanceContext();

  // Latest-value ref for balances (same pattern as stablecoinSendScreen). The
  // send-decision memos/effects read balance through this ref instead of the
  // reactive context values, so balance is dropped from their dependency
  // arrays. A burst of incoming payments then can't recompute the payment
  // method, flip uiState, or refire fee estimation mid-send. The actual send
  // still validates against live balance via sparkInfoRef.current.
  const balanceRef = useRef({
    bitcoinBalance,
    dollarBalanceSat,
    dollarBalanceToken,
  });
  balanceRef.current.bitcoinBalance = bitcoinBalance;
  balanceRef.current.dollarBalanceSat = dollarBalanceSat;
  balanceRef.current.dollarBalanceToken = dollarBalanceToken;
  const { sendWebViewRequest } = useWebView();
  const { currentWalletMnemoinc } = useActiveCustodyAccount();
  const { accountMnemoinc, contactsPrivateKey, publicKey } = useKeysContext();
  const { sparkInformation, showTokensInformation, sparkInfoRef } =
    useSparkWallet();
  const { masterInfoObject } = useGlobalContextProvider();
  const { liquidNodeInformation, fiatStats } = useNodeContext();

  const { globalContactsInformation } = useGlobalContactsInfo();
  const { theme, darkModeType } = useGlobalThemeContext();
  const { textColor, backgroundOffset, backgroundColor } = GetThemeColors();
  const { bottomPadding } = useGlobalInsets();

  const didWarnAboutBudget = useRef(null);
  const [isAmountFocused, setIsAmountFocused] = useState(true);
  const [showProgressAnimation, setShowProgressAnimation] = useState(false);
  const progressAnimationRef = useRef(null);
  const hasTriggeredFastPay = useRef(false);
  const convertedSendAmountRef = useRef(null);
  const determinePaymentMethodRef = useRef(null);
  const didRequireChoiceRef = useRef(false);
  const uiStateRef = useRef(null);
  const primaryDisplayRef = useRef(null);
  const conversionFiatStatsRef = useRef(null);
  const quoteId = useRef(null);
  const isMountedRef = useRef(true);
  // Tracks the decoded address we've already applied a local-currency default for,
  // so the phone-payment currency default runs once per address (not every render).
  const appliedLocalCurrencyRef = useRef(null);

  // Drives the SWAP_RATES_CHANGED uiState when Flashnet rate drift breaks swap viability.
  const [rateChangeDetected, setRateChangeDetected] = useState(false);
  // Captures swapUSDPriceDollars on CONFIRM_PAYMENT entry (ref = no extra re-render).
  const rateAtConfirmEntryRef = useRef(null);

  const [didSelectPaymentMethod, setDidSelectPaymentMethod] = useState(false);
  const [isDecoding, setIsDecoding] = useState(true);
  const [paymentInfo, setPaymentInfo] = useState({});
  const [lnFeeEstimate, setLnFeeEstimate] = useState(
    enteredPaymentInfo?.lnFeeEstimate ?? null,
  );
  const [isEstimatingFee, setIsEstimatingFee] = useState(false);
  const { showToast } = useToast();

  const prevSelectedPaymentInfo = useRef({
    preSelectedPaymentMethod,
    enteredInfo: enteredPaymentInfo?.inputCurrency,
    selectedPaymentMethod,
    selectedLRC20Asset: masterTokenInfo?.tokenName,
  });

  const paymentMode =
    preSelectedPaymentMethod === 'USD' ||
    enteredPaymentInfo?.inputCurrency === 'USD' ||
    selectedPaymentMethod === 'USD'
      ? 'USD'
      : 'BTC';

  const [paymentDescription, setPaymentDescription] = useState('');
  const [loadingMessage, setLoadingMessage] = useState(
    sparkInformation.didConnect
      ? t('wallet.sendPages.sendPaymentScreen.initialLoadingMessage')
      : t('wallet.sendPages.sendPaymentScreen.connectToSparkMessage'),
  );
  const [refreshDecode, setRefreshDecode] = useState(0);
  const isSendingPayment = useRef(null);
  const userPaymentMethod = selectedPaymentMethod || preSelectedPaymentMethod;
  const combinedPaymentDescription =
    paymentDescription ||
    paymentInfo?.data?.label ||
    paymentInfo?.data?.message ||
    '';

  // Payment type flags
  const isLightningPayment = paymentInfo?.paymentNetwork === 'lightning';
  const isLiquidPayment = paymentInfo?.paymentNetwork === 'liquid';
  const isBitcoinPayment = paymentInfo?.paymentNetwork === 'Bitcoin';
  const isSparkPayment = paymentInfo?.paymentNetwork === 'spark';
  const isLNURLPayment = paymentInfo?.type === InputTypes.LNURL_PAY;
  const isUsingBranta = paymentInfo?.isUsingBranta;

  const enabledLRC20 = showTokensInformation;
  const defaultToken = enabledLRC20
    ? masterInfoObject?.defaultSpendToken || 'Bitcoin'
    : 'Bitcoin';

  const useFullTokensDisplay =
    enabledLRC20 &&
    isSparkPayment &&
    paymentInfo?.data?.expectedToken !== USDB_TOKEN_ID &&
    !contactInfo;

  // const showSendMax = !dollarBalanceSat && !bitcoinBalance;

  // finds the true min swap amount
  const min_usd_swap_amount = useMemo(() => {
    return Math.round(
      dollarsToSats(swapLimits.usd, poolInfoRef.currentPriceAInB),
    );
  }, [poolInfoRef.currentPriceAInB, swapLimits]);

  const minLNURLSatAmount = isLNURLPayment
    ? paymentInfo?.data?.minSendable / 1000
    : 0;
  const maxLNURLSatAmount = isLNURLPayment
    ? paymentInfo?.data?.maxSendable / 1000
    : 0;

  const selectedLRC20Asset = masterTokenInfo?.tokenName || defaultToken;
  const seletctedToken =
    masterTokenInfo?.details ||
    sparkInformation?.tokens?.[selectedLRC20Asset] ||
    {};
  const tokenDecimals = seletctedToken?.tokenMetadata?.decimals ?? 0;
  const tokenBalance = seletctedToken?.balance ?? 0;
  const isUsingLRC20 = selectedLRC20Asset?.toLowerCase() !== 'bitcoin';

  const sendingAmount = paymentInfo?.sendAmount || 0;
  const canEditAmount = paymentInfo?.canEditPayment === true;
  const receiverExpectsCurrency = paymentInfo?.data?.expectedReceive || 'sats';

  // True when the payment amount itself meets the swap minimum for this direction.
  // For editable amounts or zero-amount invoices the user can change the value,
  // so we treat them as viable and let downstream validation enforce the limit.
  const amountViableForSwap = useMemo(() => {
    if (canEditAmount || paymentInfo?.usingZeroAmountInvoice) return true;
    const amountSat = Number(paymentInfo?.amountSat) || 0;

    // BTC→USD swap minimum is expressed in USD, converted to sats
    if (receiverExpectsCurrency === 'tokens')
      return amountSat >= min_usd_swap_amount;
    // USD→BTC swap minimum is expressed directly in sats
    return amountSat >= swapLimits.bitcoin;
  }, [
    canEditAmount,
    paymentInfo?.usingZeroAmountInvoice,
    paymentInfo?.amountSat,
    paymentInfo?.data?.expectedReceive,
    min_usd_swap_amount,
    swapLimits.bitcoin,
    receiverExpectsCurrency,
  ]);

  const isBTCOnlyPayment =
    isBitcoinPayment ||
    (isLightningPayment && paymentInfo?.usingZeroAmountInvoice);

  const resolvedPaymentMethod = useMemo(() => {
    // eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
    const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
      balanceRef.current;
    if (!paymentInfo || !Object.keys(paymentInfo || {}).length)
      return undefined;

    if (isBitcoinPayment) return 'BTC';
    if (isUsingLRC20) return 'BTC';
    if (isSparkPayment && useFullTokensDisplay) return 'BTC';
    if (isLightningPayment && paymentInfo?.usingZeroAmountInvoice) return 'BTC';

    const flashnetReady = sparkInformation?.didConnectToFlashnet;
    const receiverExpectsTokens = receiverExpectsCurrency === 'tokens';
    const amountSat = paymentInfo?.amountSat || 0;

    const canUse = method => {
      if (method === 'USD') {
        if (Number(dollarBalanceToken) < 0.01) return false;
        if (receiverExpectsTokens) return dollarBalanceSat >= amountSat;
        return (
          flashnetReady &&
          Number(dollarBalanceToken) >= swapLimits.usd &&
          amountViableForSwap
        );
      } else {
        if (!bitcoinBalance) return false;
        if (receiverExpectsTokens)
          return (
            flashnetReady &&
            bitcoinBalance >= swapLimits.bitcoin &&
            amountViableForSwap
          );
        return bitcoinBalance >= amountSat;
      }
    };

    const resolvePreferred = preferred => {
      if (canUse(preferred)) return preferred;
      const opposite = preferred === 'USD' ? 'BTC' : 'USD';
      if (canUse(opposite)) return opposite;
      return preferred;
    };

    if (preSelectedPaymentMethod)
      return resolvePreferred(preSelectedPaymentMethod);
    if (userPaymentMethod) return userPaymentMethod;
    if (enteredPaymentInfo?.inputCurrency)
      return resolvePreferred(enteredPaymentInfo.inputCurrency);

    const btcViable = canUse('BTC');
    const usdViable = canUse('USD');
    if (btcViable && usdViable)
      return receiverExpectsTokens
        ? dollarBalanceSat >= bitcoinBalance
          ? 'USD'
          : 'BTC'
        : bitcoinBalance >= dollarBalanceSat
        ? 'BTC'
        : 'USD';
    if (btcViable) return 'BTC';
    if (usdViable) return 'USD';
    return 'BTC';
  }, [
    preSelectedPaymentMethod,
    enteredPaymentInfo?.inputCurrency,
    userPaymentMethod,
    paymentInfo,
    isBitcoinPayment,
    isUsingLRC20,
    isSparkPayment,
    useFullTokensDisplay,
    isLightningPayment,
    sparkInformation?.didConnectToFlashnet,
    swapLimits,
    canEditAmount,
    min_usd_swap_amount,
    amountViableForSwap,
    receiverExpectsCurrency,
  ]);

  const paymentFee =
    resolvedPaymentMethod === 'USD' && paymentInfo?.usdPaymentFee != null
      ? (paymentInfo.usdPaymentFee || 0) + (paymentInfo.usdSupportFee || 0)
      : (paymentInfo?.paymentFee || 0) + (paymentInfo?.supportFee || 0);

  const effectivePaymentFee =
    isLightningPayment && lnFeeEstimate !== null
      ? lnFeeEstimate + (paymentInfo?.supportFee || 0)
      : paymentFee;

  const usdFiatStats = useMemo(
    () => resolveUsdFiatStats(fiatStats, swapUSDPriceDollars),
    [fiatStats, swapUSDPriceDollars],
  );
  // When arriving from a flow where the user already picked a display rate
  // (e.g. a contact send), honor that currency instead of re-deriving the
  // device-based default. Falls back to the legacy default otherwise.
  const initialDisplayCurrency = useMemo(
    () =>
      paymentDisplayCurrency ||
      getDefaultDisplayCurrency({
        paymentMode: resolvedPaymentMethod || paymentMode,
        masterInfoObject,
        fiatStats,
      }),
    [
      paymentDisplayCurrency,
      resolvedPaymentMethod,
      paymentMode,
      masterInfoObject,
      fiatStats,
    ],
  );
  const additionalRates = useMemo(
    () =>
      paymentDisplayCurrency && paymentDisplayFiatStats?.value
        ? { [paymentDisplayCurrency]: paymentDisplayFiatStats }
        : undefined,
    [paymentDisplayCurrency, paymentDisplayFiatStats],
  );
  const {
    displayCurrency,
    currencyRates,
    isLoadingRate,
    selectCurrency,
    loadAndSetCurrency,
    injectRate,
    hasUserSelectedDisplayCurrency,
  } = useDisplayCurrencyController({
    initialCurrency: initialDisplayCurrency,
    fiatStats,
    usdFiatStats,
    masterInfoObject,
    additionalRates,
  });

  const {
    primaryDisplay,
    secondaryDisplay,
    conversionFiatStats,
    convertSatsToDisplay,
    convertDisplayToSats,
    buildAmountSnapshot,
  } = useCurrencyDisplay({
    displayCurrency,
    fiatStats,
    usdFiatStats,
    currencyRates,
    masterInfoObject,
    isSendingPayment: isSendingPayment.current,
  });

  // Prefer the user's verbatim entered string (display-truth) when we carried it across
  // the accept/contact handoff and it was entered in the denomination we're now showing.
  // Only genuine fixed-from-invoice amounts (no entry) fall back to reconversion.
  // Guard keys on denomination only (fiat vs sats), not the specific currency: the contact
  // handoff pins paymentDisplayCurrency/paymentDisplayFiatStats and the confirm view hides the
  // currency switcher, so a same-denomination/different-currency mismatch cannot occur here.
  const hasEnteredDisplay =
    paymentInfo?.enteredDisplayAmount != null &&
    paymentInfo?.enteredDisplayAmount !== '' &&
    paymentInfo?.enteredDisplayDenomination === primaryDisplay.denomination;

  const displayAmount = canEditAmount
    ? sendingAmount
    : hasEnteredDisplay
    ? paymentInfo.enteredDisplayAmount
    : convertSatsToDisplay(sendingAmount);

  const convertedSendAmount = !isUsingLRC20
    ? canEditAmount
      ? convertDisplayToSats(sendingAmount) // User entered amount, convert to sats
      : Number(sendingAmount) // Fixed invoice amount, already in sats
    : Number(sendingAmount);

  // use stablepool info ref so the fiat amount doesnt change in between inputs leading to a false amount being sent.
  const fiatValueConvertedSendAmount = Math.round(
    satsToDollars(
      convertedSendAmount,
      enteredPaymentInfo?.stablePoolInfoRef?.currentPriceAInB ||
        poolInfoRef.currentPriceAInB,
    ).toFixed(2) * Math.pow(10, 6),
  );

  const requiresUserMethodSelection = useMemo(() => {
    // eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
    const { bitcoinBalance, dollarBalanceSat } = balanceRef.current;
    if (resolvedPaymentMethod === undefined) return false;
    if (
      !!preSelectedPaymentMethod ||
      useFullTokensDisplay ||
      isUsingLRC20 ||
      didSelectPaymentMethod
    )
      return false;

    if (!sparkInformation?.didConnectToFlashnet) return false;

    if (isBitcoinPayment) return false;

    if (isLightningPayment && paymentInfo?.usingZeroAmountInvoice) return false;

    const formattedFee = isLightningPayment ? effectivePaymentFee : 0;

    const hasEnoughBTC = bitcoinBalance >= convertedSendAmount + formattedFee;
    const hasEnoughUSD = dollarBalanceSat >= convertedSendAmount + formattedFee;

    const canSendWithBTC =
      resolvedPaymentMethod === 'BTC' && receiverExpectsCurrency === 'sats'
        ? hasEnoughBTC
        : hasEnoughBTC && amountViableForSwap;

    const canSendWIthUSD =
      resolvedPaymentMethod === 'USD' && receiverExpectsCurrency === 'tokens'
        ? hasEnoughUSD
        : hasEnoughUSD && amountViableForSwap;

    if (
      (canSendWithBTC && canSendWIthUSD) ||
      (!canSendWithBTC && !canSendWIthUSD)
    )
      return true;
    else return false;
  }, [
    isBitcoinPayment,
    useFullTokensDisplay,
    isUsingLRC20,
    didSelectPaymentMethod,
    sparkInformation?.didConnectToFlashnet,
    paymentInfo?.data?.expectedReceive,
    amountViableForSwap,
    resolvedPaymentMethod,
    receiverExpectsCurrency,
    preSelectedPaymentMethod,
    isLightningPayment,
  ]);

  const { shouldWarn } = useBudgetWarning(convertedSendAmount);

  useEffect(() => {
    primaryDisplayRef.current = primaryDisplay;
  }, [primaryDisplay]);
  useEffect(() => {
    conversionFiatStatsRef.current = conversionFiatStats;
  }, [conversionFiatStats]);

  useEffect(() => {
    return () => {
      isMountedRef.current = false;
    };
  }, []);

  useEffect(() => {
    determinePaymentMethodRef.current = resolvedPaymentMethod;
  }, [resolvedPaymentMethod]);

  const estimateLightningFee = useCallback(
    async (amount, id) => {
      // eslint-disable-next-line no-shadow -- read frozen balance, decoupled from live deps
      const { bitcoinBalance, dollarBalanceSat, dollarBalanceToken } =
        balanceRef.current;
      if (!amount || !isLightningPayment || !canEditAmount) {
        setIsEstimatingFee(false);
        return;
      }
      if (quoteId.current !== id) return;

      const balance =
        resolvedPaymentMethod === 'USD' ? dollarBalanceSat : bitcoinBalance;
      const bufferAmount = amount * 1.1;

      // Skip if balance easily covers the send + estimated fee buffer, or if
      // already over balance (validation will catch it without needing a fee)
      if (bufferAmount < balance || amount > balance) {
        setIsEstimatingFee(false);
        return;
      }

      try {
        const formattedSparkPaymentInfo = formatSparkPaymentAddress(
          paymentInfo,
          false,
        );
        let invoice = formattedSparkPaymentInfo.address;
        if (paymentInfo.type === InputTypes.LNURL_PAY && !invoice) {
          const invoiceResponse = await getLNAddressForLiquidPayment(
            paymentInfo.decodedInput,
            amount,
          );

          if (!invoiceResponse.pr) throw new Error('No invoice received');
          invoice = invoiceResponse.pr;
          setPaymentInfo(prev => ({
            ...prev,
            data: { ...(prev.data || {}), invoice },
          }));
        }

        if (!invoice) {
          setIsEstimatingFee(false);
          return;
        }
        if (resolvedPaymentMethod === 'USD') {
          const quote = await getLightningPaymentQuote(
            currentWalletMnemoinc,
            invoice,
            USD_ASSET_ADDRESS,
            undefined,
            undefined,
            { amountSats: amount },
          );
          if (!quote.didWork)
            throw new Error(quote.error || 'Fee quote failed');
          if (quoteId.current !== id) return;
          const estimatedAmmFeeSat = Math.round(
            dollarsToSats(
              quote.quote.estimatedAmmFee / Math.pow(10, 6),
              poolInfoRef.currentPriceAInB,
            ),
          );
          const dollarAmountRequired = quote.quote.tokenAmountRequired;
          const userDollarBalance = dollarBalanceToken * Math.pow(10, 6);
          const fee = quote.quote.estimatedLightningFee + estimatedAmmFeeSat;
          if (dollarAmountRequired > userDollarBalance) {
            showToast({
              type: 'error',
              title: t('errormessages.lightningAmountRequiredWarning', {
                amount: displayCorrectDenomination({
                  amount: parseFloat(
                    formatTokensNumber(quote.quote.tokenAmountRequired, 6),
                  ).toFixed(2),
                  masterInfoObject: {
                    ...masterInfoObject,
                    userBalanceDenomination: 'fiat',
                  },
                  fiatStats,
                  convertAmount: false,
                  forceCurrency: 'USD',
                }),
              }),
              duration: 6000,
            });
          }
          setLnFeeEstimate(fee);
          setPaymentInfo(prev => ({
            ...prev,
            paymentFee: fee,
            supportFee: prev.supportFee ?? 0,
            swapPaymentQuote: {
              ...quote.quote,
              bitcoinBalance,
              dollarBalanceSat,
            },
          }));
        } else {
          const feeResult = await sparkPaymenWrapper({
            getFee: true,
            paymentType: 'lightning',
            address: invoice,
            amountSats: amount,
            masterInfoObject,
            sparkInformation: sparkInfoRef.current,
            mnemonic: currentWalletMnemoinc,
            sendWebViewRequest,
          });
          if (!feeResult.didWork) throw new Error('Fee estimation failed');
          if (quoteId.current !== id) return;
          const fee = feeResult.fee;
          if (fee + amount > bitcoinBalance) {
            showToast({
              type: 'error',
              title: t('errormessages.lightningAmountFeeWarning', {
                amount: displayCorrectDenomination({
                  amount: fee,
                  masterInfoObject: {
                    ...masterInfoObject,
                    userBalanceDenomination: 'sats',
                  },
                  fiatStats,
                }),
              }),
              duration: 6000,
            });
          }
          setLnFeeEstimate(fee);
          setPaymentInfo(prev => ({
            ...prev,
            paymentFee: fee,
            supportFee: prev.supportFee ?? 0,
          }));
        }
      } catch {
        showToast({
          type: 'error',
          title: t('wallet.sendPages.sendPaymentScreen.feeEstimateError'),
        });
      } finally {
        if (quoteId.current === id) {
          setIsEstimatingFee(false);
        }
      }
    },
    [
      isLightningPayment,
      canEditAmount,
      resolvedPaymentMethod,
      paymentInfo,
      currentWalletMnemoinc,
      masterInfoObject,
      fiatStats,
      sparkInfoRef,
      sendWebViewRequest,
      showToast,
      t,
    ],
  );

  const debouncedEstimateFee = useDebounce(estimateLightningFee, 600);

  useEffect(() => {
    if (requiresUserMethodSelection && !didRequireChoiceRef.current) {
      didRequireChoiceRef.current = true;
    }
  }, [requiresUserMethodSelection]);

  // Fast pay logic
  const canUseFastPay =
    sparkInformation.didConnect &&
    Object.keys(paymentInfo || {}).length > 0 &&
    masterInfoObject[QUICK_PAY_STORAGE_KEY]?.isFastPayEnabled &&
    masterInfoObject[QUICK_PAY_STORAGE_KEY]?.fastPayThresholdSats >=
      convertedSendAmount &&
    !isUsingLRC20 &&
    (!didRequireChoiceRef.current || didSelectPaymentMethod) &&
    !requiresUserMethodSelection &&
    convertedSendAmount >= effectivePaymentFee &&
    !shouldWarn;

  const uiState = useMemo(() => {
    if (canEditAmount && !isSendingPayment.current) {
      return 'EDIT_AMOUNT'; // Show number pad + description input
    }

    // Rate-change intercept: show before CHOOSE_METHOD / CONFIRM_PAYMENT so it
    // takes over the screen whenever the Flashnet rate broke swap viability.
    if (rateChangeDetected) {
      return 'SWAP_RATES_CHANGED';
    }

    if (
      requiresUserMethodSelection &&
      !isSendingPayment.current &&
      !isBitcoinPayment &&
      !isUsingLRC20 &&
      !preSelectedPaymentMethod
    ) {
      return 'CHOOSE_METHOD'; // Show info screen with button to select method
    }

    return 'CONFIRM_PAYMENT'; // Show swipe button
  }, [
    canEditAmount,
    rateChangeDetected,
    requiresUserMethodSelection,
    didSelectPaymentMethod,
    isBitcoinPayment,
    isUsingLRC20,
    canUseFastPay,
    preSelectedPaymentMethod,
  ]);

  useEffect(() => {
    uiStateRef.current = uiState;
  }, [uiState]);

  useEffect(() => {
    if (
      uiState === 'CONFIRM_PAYMENT' &&
      shouldWarn &&
      !didWarnAboutBudget.current &&
      !isSendingPayment.current &&
      !isDecoding
    ) {
      didWarnAboutBudget.current = true;
      navigate.navigate('CustomHalfModal', {
        wantedContent: 'nearBudgetLimitWarning',
        sliderHight: 0.6,
        sendingAmount: convertedSendAmount,
      });
    }
  }, [uiState, shouldWarn, convertedSendAmount, isDecoding]);

  useEffect(() => {
    if (
      prevSelectedPaymentInfo.current.preSelectedPaymentMethod !==
        preSelectedPaymentMethod ||
      prevSelectedPaymentInfo.current.enteredInfo !==
        enteredPaymentInfo?.inputCurrency ||
      prevSelectedPaymentInfo.current.selectedPaymentMethod !==
        selectedPaymentMethod ||
      prevSelectedPaymentInfo.current.selectedLRC20Asset !== selectedLRC20Asset
    ) {
      console.log(
        'Payment method or input currency changed, resetting payment info',
      );
      if (uiStateRef.current !== 'EDIT_AMOUNT') return;
      console.log('Resetting payment info for new selection');
      setPaymentInfo(prev => ({
        ...prev,
        sendAmount: '',
        feeQuote: undefined,
        swapPaymentQuote: undefined,
        paymentFee: 0,
        supportFee: 0,
      }));
      prevSelectedPaymentInfo.current = {
        preSelectedPaymentMethod,
        enteredInfo: enteredPaymentInfo?.inputCurrency,
        selectedPaymentMethod,
        selectedLRC20Asset,
      };
    }
  }, [
    preSelectedPaymentMethod,
    enteredPaymentInfo?.inputCurrency,
    selectedPaymentMethod,
    selectedLRC20Asset,
  ]);

  const paymentValidation = usePaymentValidation({
    paymentInfo,
    convertedSendAmount,
    paymentFee: effectivePaymentFee,
    determinePaymentMethod: resolvedPaymentMethod,
    selectedPaymentMethod: userPaymentMethod,
    bitcoinBalance,
    dollarBalanceSat,
    dollarBalanceToken,
    min_usd_swap_amount,
    swapLimits,
    isUsingLRC20,
    seletctedToken,
    minLNURLSatAmount,
    maxLNURLSatAmount,
    isDecoding,
    canEditAmount,
    t,
    masterInfoObject,
    fiatStats,
    inputDenomination: primaryDisplay.denomination,
    primaryDisplay,
    conversionFiatStats,
    sparkInformation,
    poolInfoRef,
  });
  console.log(paymentValidation);

  const canSendPayment =
    paymentValidation.canProceed &&
    sendingAmount !== 0 &&
    uiState === 'CONFIRM_PAYMENT';

  const isUsingFastPay = canUseFastPay && canSendPayment && !canEditAmount;

  // Rate-sensitive swap path: only Flashnet swaps (USD→BTC / BTC→USDB) are affected
  // by live rate changes. Mirrors needsSwap in paymentValidation.
  const needsRateSwap =
    (resolvedPaymentMethod === 'USD' && receiverExpectsCurrency === 'sats') ||
    (resolvedPaymentMethod === 'BTC' && receiverExpectsCurrency === 'tokens');

  // Snapshot + detection effect.
  // Captures the rate on CONFIRM_PAYMENT entry; when a subsequent rate tick
  // breaks swap viability (convertedSendAmount shrinks, min_usd_swap_amount rises),
  // sets rateChangeDetected → transitions to SWAP_RATES_CHANGED uiState.
  // Resets completely when the user leaves the confirm flow.
  useEffect(() => {
    if (isDecoding) return;
    if (uiState === 'CONFIRM_PAYMENT') {
      // Capture rate once on entry
      if (rateAtConfirmEntryRef.current === null) {
        rateAtConfirmEntryRef.current = swapUSDPriceDollars;
      }
      // Detect drift that broke viability
      if (
        rateAtConfirmEntryRef.current !== null &&
        swapUSDPriceDollars !== rateAtConfirmEntryRef.current &&
        !paymentValidation.canProceed &&
        needsRateSwap &&
        !isSendingPayment.current
      ) {
        setRateChangeDetected(true);
      }
    } else if (uiState !== 'SWAP_RATES_CHANGED') {
      // Leaving the confirm flow entirely (EDIT / CHOOSE / back) — full reset.
      // Guard against SWAP_RATES_CHANGED so the state doesn't clear itself.
      rateAtConfirmEntryRef.current = null;
      setRateChangeDetected(false);
    }
  }, [
    uiState,
    swapUSDPriceDollars,
    paymentValidation.canProceed,
    needsRateSwap,
    isDecoding,
  ]);

  const handleRateChangedReset = useCallback(() => {
    rateAtConfirmEntryRef.current = null;
    setRateChangeDetected(false);
    if (isLNURLPayment || isSparkPayment) {
      // Full reset — mirrors hasParamsChanged effect sequence exactly
      setIsAmountFocused(true);
      setPaymentInfo({});
      setLnFeeEstimate(null);
      setIsEstimatingFee(false);
      isSendingPayment.current = null;
      setPaymentDescription('');
      hasTriggeredFastPay.current = false;
      didRequireChoiceRef.current = false;
      setLoadingMessage(
        sparkInformation.didConnect && sparkInformation.identityPubKey
          ? t('wallet.sendPages.sendPaymentScreen.initialLoadingMessage')
          : t('wallet.sendPages.sendPaymentScreen.connectToSparkMessage'),
      );
      setDidSelectPaymentMethod(false);
      setShowProgressAnimation(false);
      setRefreshDecode(x => x + 1);
    } else {
      navigate.goBack();
    }
  }, [
    isLNURLPayment,
    isSparkPayment,
    navigate,
    sparkInformation.didConnect,
    sparkInformation.identityPubKey,
    t,
  ]);

  const errorMessageNavigation = useCallback(
    reason => {
      if (!isMountedRef.current) return;
      navigate.navigate('ConfirmPaymentScreen', {
        btcAdress: '',
        fromPage: '',
        publishMessageFunc: null,
        comingFromAccept: null,
        enteredPaymentInfo: {},
        errorMessage:
          reason ||
          t('wallet.sendPages.sendPaymentScreen.fallbackErrorMessage'),
      });
    },
    [navigate, t],
  );

  useEffect(() => {
    const currentParams = { btcAdress };
    const prevParams = paramsRef.current;

    const hasParamsChanged =
      currentParams.btcAdress &&
      currentParams.btcAdress !== prevParams.btcAdress;

    if (hasParamsChanged) {
      setIsAmountFocused(true);
      setPaymentInfo({});
      setLnFeeEstimate(null);
      setIsEstimatingFee(false);
      isSendingPayment.current = null;
      setPaymentDescription('');
      hasTriggeredFastPay.current = false;
      didRequireChoiceRef.current = false;
      setLoadingMessage(
        !!sparkInformation.didConnect && !!sparkInformation.identityPubKey
          ? t('wallet.sendPages.sendPaymentScreen.initialLoadingMessage')
          : t('wallet.sendPages.sendPaymentScreen.connectToSparkMessage'),
      );
      setDidSelectPaymentMethod(false);
      setShowProgressAnimation(false);
      setRefreshDecode(x => x + 1);
      paramsRef.current = currentParams;
    }
  }, [
    btcAdress,
    sparkInformation.didConnect,
    sparkInformation.identityPubKey,
    t,
  ]);

  useEffect(() => {
    convertedSendAmountRef.current = convertedSendAmount;
  }, [convertedSendAmount]);

  useEffect(() => {
    if (!canEditAmount || !isLightningPayment) return;
    setLnFeeEstimate(null);
    setPaymentInfo(prev => ({
      ...prev,
      data: { ...(prev.data || {}), invoice: '' },
      paymentFee: 0,
    }));
    if (convertedSendAmount > 0) {
      const id = customUUID();
      quoteId.current = id;
      setIsEstimatingFee(true);
      debouncedEstimateFee(convertedSendAmount, id);
    }
  }, [convertedSendAmount, canEditAmount, isLightningPayment]);

  useEffect(() => {
    async function decodePayment() {
      crashlyticsLogReport('Starting decode address');
      setIsDecoding(true);
      await decodeSendAddress({
        fiatStats,
        btcAdress: paramsRef.current.btcAdress,
        goBackFunction: errorMessageNavigation,
        setPaymentInfo,
        liquidNodeInformation,
        masterInfoObject: {
          ...masterInfoObject,
          userBalanceDenomination:
            primaryDisplayRef.current?.denomination || 'sats',
        },
        // setWebViewArgs,
        // webViewRef,
        navigate,
        // maxZeroConf:
        //   minMaxLiquidSwapAmounts?.submarineSwapStats?.limits?.maximalZeroConf,
        comingFromAccept: enteredPaymentInfo.fromContacts,
        enteredPaymentInfo,
        setLoadingMessage,
        paymentInfo,
        fromPage,
        sparkInformation,
        seletctedToken,
        currentWalletMnemoinc,
        t,
        sendWebViewRequest,
        contactInfo,
        globalContactsInformation,
        accountMnemoinc,
        usablePaymentMethod:
          userPaymentMethod || determinePaymentMethodRef.current,
        bitcoinBalance,
        dollarBalanceSat,
        convertedSendAmount: convertedSendAmountRef.current,
        poolInfoRef,
        swapLimits,
        // usd_multiplier_coefiicent,
        min_usd_swap_amount,
        primaryDisplay: primaryDisplayRef.current,
        conversionFiatStats: conversionFiatStatsRef.current,
        contactsPrivateKey,
        publicKey,
      });
      setIsDecoding(false);
    }

    if (!sparkInformation.didConnect || !sparkInformation.identityPubKey)
      return;
    if (isSendingPayment.current) return;

    requestAnimationFrame(() => {
      decodePayment();
    });
  }, [
    sparkInformation.didConnect,
    sparkInformation.identityPubKey,
    refreshDecode,
    // selectedPaymentMethod,
  ]);

  // After an LNURL pay decode, default the amount input to the payment location's
  // local fiat currency for phone-number payments, and seed any LNURL-advertised
  // rate so a manual switch to that currency uses the provided rate. Runs once per
  // decoded address and never overrides a manual currency selection.
  useEffect(() => {
    const country = paymentInfo?.phonePaymentCountry;
    const descriptor = paymentInfo?.lnurlCurrency || null;

    // Nothing to do for non-phone pays that don't advertise a currency.
    if (paymentDisplayCurrency && paymentDisplayFiatStats) return;
    if (!country && !descriptor) return;
    if (hasUserSelectedDisplayCurrency) return;

    const address = paymentInfo?.data?.address;
    if (appliedLocalCurrencyRef.current === address) return;

    const code = (
      descriptor?.code ||
      (country ? PROVIDER_COUNTRY_CURRENCY[country] : '') ||
      ''
    ).toUpperCase();
    if (!code || !fiatCurrencies.some(c => c.id === code)) return;

    appliedLocalCurrencyRef.current = address;

    const rate = lnurlCurrencyToRate(descriptor);
    if (rate) {
      // Phone pay: seed the rate and switch to it. Non-phone: seed only, so the
      // provided rate is used if the user manually switches to this currency.
      injectRate(code, rate, { setAsDisplay: !!country });
    } else if (country) {
      // Phone pay with no usable LNURL rate: fall back to our internal rate. If
      // that fails, the existing BTC/device-currency default stays.
      loadAndSetCurrency(code);
    }
  }, [
    paymentInfo,
    hasUserSelectedDisplayCurrency,
    injectRate,
    loadAndSetCurrency,
  ]);

  // Fast pay auto-trigger
  useEffect(() => {
    if (
      !isUsingFastPay ||
      hasTriggeredFastPay.current ||
      isSendingPayment.current
    )
      return;

    setShowProgressAnimation(true);

    if (progressAnimationRef.current) {
      requestAnimationFrame(() => {
        progressAnimationRef.current.startAtBeginning();
      });
    }

    const fastPayTrigger = setTimeout(() => {
      hasTriggeredFastPay.current = true;
      if (progressAnimationRef.current) {
        progressAnimationRef.current.startProgress();
      }
      sendPayment();
    }, 250);

    return () => {
      clearTimeout(fastPayTrigger);
    };
  }, [isUsingFastPay]);

  const publishMessageFuncForContact = useCallback(
    txid => {
      const UUID = customUUID();
      const sendObject = {
        amountMsat: convertedSendAmountRef.current * 1000,
        uuid: UUID,
        wasSeen: null,
        didSend: null,
        isRedeemed: null,
        description: combinedPaymentDescription || '',
        isRequest: false,
        paymentDenomination:
          paymentInfo.data.expectedReceive === 'tokens' ? 'USD' : 'BTC',
        amountDollars:
          paymentInfo.data.expectedReceive === 'tokens'
            ? satsToDollars(
                convertedSendAmount,
                poolInfoRef.currentPriceAInB,
              ).toFixed(2)
            : null,
        ...(globalContactsInformation.myProfile?.uniqueName
          ? {
              senderProfileSnapshot: {
                uniqueName: globalContactsInformation.myProfile.uniqueName,
              },
            }
          : {}),
      };
      publishMessage({
        toPubKey: selectedContact.uuid,
        fromPubKey: globalContactsInformation.myProfile.uuid,
        data: {
          ...sendObject,
          txid,
          name:
            globalContactsInformation.myProfile?.name ||
            globalContactsInformation.myProfile?.uniqueName,
        },
        globalContactsInformation,
        selectedContact,
        isLNURLPayment: selectedContact?.isLNURL,
        privateKey: contactsPrivateKey,
        retrivedContact,
        currentTime: Date.now(),
        masterInfoObject,
      });
    },
    [
      selectedContact,
      retrivedContact,
      globalContactsInformation,
      contactsPrivateKey,
      masterInfoObject,
      combinedPaymentDescription,
      paymentInfo,
    ],
  );
  const effectivePublishMessageFunc =
    paymentInfo?.publishMessageFunc ||
    publishMessageFunc ||
    (selectedContact ? publishMessageFuncForContact : null);

  const sendPayment = useCallback(async () => {
    if (!paymentValidation.isValid) {
      const error = paymentValidation.getErrorMessage(
        paymentValidation.primaryError,
      );
      navigate.navigate('ErrorScreen', { errorMessage: error });
      return;
    }

    if (isSendingPayment.current) return;

    isSendingPayment.current = true;
    setShowProgressAnimation(true);

    try {
      const formattedSparkPaymentInfo = formatSparkPaymentAddress(
        paymentInfo,
        selectedLRC20Asset?.toLowerCase() !== 'bitcoin',
      );

      const memo =
        paymentInfo.type === InputTypes.BOLT11
          ? enteredPaymentInfo?.description || combinedPaymentDescription
          : combinedPaymentDescription || enteredPaymentInfo?.description;

      const paymentObject = {
        getFee: false,
        ...formattedSparkPaymentInfo,
        isUsingLRC20,
        amountSats: isUsingLRC20
          ? paymentInfo?.sendAmount * 10 ** tokenDecimals
          : convertedSendAmount,
        masterInfoObject,
        fee: effectivePaymentFee,
        memo,
        userBalance: bitcoinBalance,
        sparkInformation: sparkInfoRef.current,
        feeQuote: paymentInfo.feeQuote,
        swapPaymentQuote: paymentInfo.swapPaymentQuote,
        usingZeroAmountInvoice: paymentInfo.usingZeroAmountInvoice,
        seletctedToken: selectedLRC20Asset,
        mnemonic: currentWalletMnemoinc,
        sendWebViewRequest,
        contactInfo,
        fromMainSendScreen: true,
        usablePaymentMethod: resolvedPaymentMethod,
        paymentInfo,
        fiatValueConvertedSendAmount,
        poolInfoRef,
        extraDetails: paymentInfo?.isUsingBranta
          ? {
              brantaMerchantName: paymentInfo.brantaMerchantName,
              brantaMerchantLogo: paymentInfo.brantaMerchantLogo,
            }
          : {},
      };

      const paymentResponse = await sparkPaymenWrapper(paymentObject);

      // Handle deferred save if identityPubKey wasn't available during payment
      if (paymentResponse.shouldSave) {
        let retries = 0;
        const maxRetries = 20; // 10 seconds max wait

        while (!sparkInfoRef.current.identityPubKey && retries < maxRetries) {
          console.log('WATIINT FOR IDENTITY PUBKEY');
          await new Promise(res => setTimeout(res, 500));
          retries++;
        }

        if (sparkInfoRef.current.identityPubKey) {
          const tx = {
            ...paymentResponse.response,
            accountId: sparkInfoRef.current.identityPubKey,
          };
          await bulkUpdateSparkTransactions([tx], 'paymentWrapperTx', 0);
        } else {
          console.error('Failed to get identityPubKey after waiting');
        }

        isSendingPayingEventEmiiter.emit(SENDING_PAYMENT_EVENT_NAME, false);
      }

      if (progressAnimationRef.current) {
        progressAnimationRef.current.completeProgress();
        await new Promise(res => setTimeout(res, 600));
      }

      if (paymentResponse.didWork) {
        if (
          (fromPage === 'contacts' && paymentResponse.response?.id) ||
          fromPage === 'paylink'
        ) {
          effectivePublishMessageFunc(paymentResponse.response.id);
        }
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            navigate.reset({
              index: 0,
              routes: [
                {
                  name: 'HomeAdmin',
                  params: {
                    screen: 'Home',
                  },
                },
                {
                  name: 'ConfirmTxPage',
                  params: {
                    transaction: paymentResponse.response,
                    lnurlAddress:
                      paymentInfo?.type === InputTypes.LNURL_PAY
                        ? normalizeLNURLAddress(paymentInfo?.data?.address)
                        : undefined,
                    blitzContactInfo: paymentInfo?.blitzContactInfo,
                    paymentDisplay: primaryDisplayRef.current,
                    displayAmount,
                  },
                },
              ],
            });
          });
        });
      } else {
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            navigate.reset({
              index: 0,
              routes: [
                {
                  name: 'HomeAdmin',
                  params: {
                    screen: 'Home',
                  },
                },
                {
                  name: 'ConfirmTxPage',
                  params: {
                    transaction: paymentResponse.response,
                    error: paymentResponse.error,
                    lnurlAddress:
                      paymentInfo?.type === InputTypes.LNURL_PAY
                        ? normalizeLNURLAddress(paymentInfo?.data?.address)
                        : undefined,
                    blitzContactInfo: paymentInfo?.blitzContactInfo,
                    paymentDisplay: primaryDisplayRef.current,
                    displayAmount,
                  },
                },
              ],
            });
          });
        });
      }
    } catch (error) {
      console.error('Error in sendPayment:', error);
      // Reset state on error
      isSendingPayment.current = false;
      setShowProgressAnimation(false);
      // Optionally show error to user
      errorMessageNavigation(error.message);
    }
  }, [
    canSendPayment,
    paymentInfo,
    selectedLRC20Asset,
    enteredPaymentInfo,
    combinedPaymentDescription,
    isUsingLRC20,
    tokenDecimals,
    convertedSendAmount,
    masterInfoObject,
    effectivePaymentFee,
    bitcoinBalance,
    sparkInformation,
    currentWalletMnemoinc,
    sendWebViewRequest,
    contactInfo,
    fromPage,
    effectivePublishMessageFunc,
    navigate,
    errorMessageNavigation,
    resolvedPaymentMethod,
    fiatValueConvertedSendAmount,
    paymentValidation,
    displayAmount,
  ]);

  const handleSelectPaymentMethod = useCallback(
    showNextScreen => {
      if (showNextScreen) {
        if (!paymentValidation.isValid) {
          const error = paymentValidation.getErrorMessage(
            paymentValidation.primaryError,
          );
          navigate.navigate('ErrorScreen', { errorMessage: error });
          return;
        }

        setDidSelectPaymentMethod(true);
      } else {
        navigate.navigate('CustomHalfModal', {
          wantedContent: 'SelectPaymentMethod',
          selectedPaymentMethod: resolvedPaymentMethod,
        });
      }
    },
    [navigate, paymentValidation, resolvedPaymentMethod],
  );
  const handleSelectTokenPress = useCallback(() => {
    navigate.navigate('CustomHalfModal', {
      wantedContent: 'SelectLRC20Token',
    });
  }, [navigate]);

  const handleEmoji = newDescription => {
    setPaymentDescription(newDescription);
  };

  const openCurrencyPicker = () => {
    if (!isAmountFocused) return;
    if (isUsingLRC20) return;
    if (isSendingPayment.current) return;

    navigate.navigate('CustomHalfModal', {
      wantedContent: 'displayCurrencySelect',
      sliderHight: 0.6,
      currentCurrency: displayCurrency,
      onSelectCurrency: async code => {
        const response = await selectCurrency(code);
        if (!response?.didWork) return;
        if (!canEditAmount) return;
        setPaymentInfo(prev => ({
          ...prev,
          sendAmount: '',
          feeQuote: undefined,
          swapPaymentQuote: undefined,
          paymentFee: 0,
          supportFee: 0,
        }));
      },
    });
  };

  const memorizedKeyboardStyle = useMemo(() => {
    return {
      paddingBottom: !isAmountFocused ? 0 : bottomPadding,
    };
  }, [isAmountFocused, bottomPadding]);

  const handleBrandaVerificationUrl = useCallback(() => {
    navigate.navigate('CustomWebView', {
      headerText: 'Branta',
      webViewURL: paymentInfo?.verificationURL,
    });
  }, [paymentInfo?.verificationURL, navigate, t]);

  const sendingAsset =
    selectedLRC20Asset === 'Bitcoin'
      ? !isLightningPayment &&
        !isBitcoinPayment &&
        !(isSparkPayment && receiverExpectsCurrency === 'sats')
        ? t('constants.dollars_upper')
        : t('constants.bitcoin_upper')
      : seletctedToken?.tokenMetadata?.tokenTicker;

  if (
    (!Object.keys(paymentInfo).length && !errorMessage) ||
    !sparkInformation.didConnect
  ) {
    return (
      <GlobalThemeView useStandardWidth={true}>
        <CustomSettingsTopBar />
        <FullLoadingScreen text={loadingMessage} />
      </GlobalThemeView>
    );
  }

  if (errorMessage) {
    return <ErrorWithPayment reason={errorMessage} />;
  }

  return (
    <CustomKeyboardAvoidingView globalThemeViewStyles={memorizedKeyboardStyle}>
      <View style={styles.replacementContainer}>
        <CustomSettingsTopBar
          label={t('constants.send')}
          showLeftImage={isUsingBranta}
          iconNew="BadgeCheck"
          leftImageStyles={{ height: 25 }}
          leftImageFunction={handleBrandaVerificationUrl}
          rightContent={
            !isUsingLRC20 && uiState !== 'CONFIRM_PAYMENT' ? (
              <CurrencySwitchButton
                displayCurrency={displayCurrency}
                onPress={openCurrencyPicker}
                disabled={isLoadingRate}
              />
            ) : null
          }
        />
        <ScrollView contentContainerStyle={styles.balanceScrollContainer}>
          {/* Amount display */}
          {uiState !== 'SWAP_RATES_CHANGED' && (
            <View>
              <FormattedBalanceInput
                maxWidth={0.9}
                amountValue={displayAmount}
                inputDenomination={primaryDisplay.denomination}
                forceCurrency={primaryDisplay.forceCurrency}
                forceFiatStats={primaryDisplay.forceFiatStats}
                activeOpacity={!sendingAmount ? 0.5 : 1}
                customCurrencyCode={
                  isUsingLRC20 ? seletctedToken?.tokenMetadata?.tokenTicker : ''
                }
                maxDecimals={isUsingLRC20 ? tokenDecimals : 2}
              />
              {uiState === 'CONFIRM_PAYMENT' && !isUsingLRC20 && (
                <SecondaryAmountDisplay
                  amountSats={convertedSendAmount}
                  secondaryDisplay={secondaryDisplay}
                />
              )}
            </View>
          )}

          {/* Send max button for edit mode */}
          {/* {!useAltLayout && uiState === 'EDIT_AMOUNT' && showSendMax && (
            <SendMaxComponent
              fiatStats={fiatStats}
              sparkInformation={sparkInformation}
              paymentInfo={paymentInfo}
              setPaymentInfo={setPaymentInfo}
              masterInfoObject={masterInfoObject}
              paymentFee={paymentFee}
              paymentType={paymentInfo?.paymentNetwork}
              // minMaxLiquidSwapAmounts={minMaxLiquidSwapAmounts}
              selectedLRC20Asset={selectedLRC20Asset}
              seletctedToken={seletctedToken}
              useAltLayout={useAltLayout}
            />
          )} */}

          {/* Fee info for fixed amount */}
          {uiState === 'CONFIRM_PAYMENT' && (
            <SendTransactionFeeInfo
              paymentFee={effectivePaymentFee}
              isLightningPayment={isLightningPayment}
              isLiquidPayment={isLiquidPayment}
              isBitcoinPayment={isBitcoinPayment}
              isSparkPayment={isSparkPayment}
              isDecoding={isDecoding}
            />
          )}

          {/* Invoice info */}
          {uiState === 'CONFIRM_PAYMENT' && (
            <InvoiceInfo
              paymentInfo={paymentInfo}
              contactInfo={contactInfo || paymentInfo?.blitzContactInfo}
              fromPage={
                fromPage || (paymentInfo?.blitzContactInfo ? 'contacts' : '')
              }
              theme={theme}
              darkModeType={darkModeType}
              isUsingBranta={isUsingBranta}
            />
          )}
          {uiState === 'CHOOSE_METHOD' && (
            <ChoosePaymentMethod
              theme={theme}
              darkModeType={darkModeType}
              determinePaymentMethod={resolvedPaymentMethod}
              handleSelectPaymentMethod={handleSelectPaymentMethod}
              bitcoinBalance={bitcoinBalance}
              dollarBalanceToken={dollarBalanceToken}
              masterInfoObject={masterInfoObject}
              fiatStats={fiatStats}
              uiState={uiState}
              t={t}
              showPayWith={true}
            />
          )}

          {/* SWAP_RATES_CHANGED — rate drifted and broke swap viability */}
          {uiState === 'SWAP_RATES_CHANGED' && <SwapRatesChangedState />}
        </ScrollView>

        {/* EDIT_AMOUNT State - Show input controls */}
        {uiState === 'EDIT_AMOUNT' && (
          <>
            {/* Token selector for Spark LRC20 payments */}
            {enabledLRC20 &&
              paymentInfo.type === 'spark' &&
              canEditAmount &&
              useFullTokensDisplay && (
                <ChooseLRC20TokenContainer
                  theme={theme}
                  darkModeType={darkModeType}
                  determinePaymentMethod={resolvedPaymentMethod}
                  handleSelectPaymentMethod={handleSelectTokenPress}
                  bitcoinBalance={bitcoinBalance}
                  dollarBalanceToken={dollarBalanceToken}
                  masterInfoObject={masterInfoObject}
                  fiatStats={fiatStats}
                  uiState={uiState}
                  seletctedToken={seletctedToken}
                  selectedLRC20Asset={selectedLRC20Asset}
                  t={t}
                />
              )}
            {!(
              enabledLRC20 &&
              paymentInfo.type === 'spark' &&
              canEditAmount &&
              useFullTokensDisplay
            ) && (
              <ChoosePaymentMethod
                theme={theme}
                darkModeType={darkModeType}
                determinePaymentMethod={resolvedPaymentMethod}
                handleSelectPaymentMethod={handleSelectPaymentMethod}
                bitcoinBalance={bitcoinBalance}
                dollarBalanceToken={dollarBalanceToken}
                masterInfoObject={masterInfoObject}
                fiatStats={fiatStats}
                uiState={uiState}
                t={t}
                showBitcoinCardOnly={isBTCOnlyPayment}
                showPayWith={true}
              />
            )}
            <CustomSearchInput
              onFocusFunction={() => setIsAmountFocused(false)}
              onBlurFunction={() => setIsAmountFocused(true)}
              placeholderText={t('constants.paymentDescriptionPlaceholder')}
              setInputText={setPaymentDescription}
              inputText={combinedPaymentDescription}
              textInputMultiline={true}
              textAlignVertical={'baseline'}
              maxLength={paymentInfo?.data?.commentAllowed || 150}
              containerStyles={{
                width: INSET_WINDOW_WIDTH,
                marginTop: 10,
              }}
            />

            {isAmountFocused && (
              <NumberInputSendPage
                paymentInfo={paymentInfo}
                setPaymentInfo={setPaymentInfo}
                fiatStats={conversionFiatStats}
                selectedLRC20Asset={selectedLRC20Asset}
                seletctedToken={seletctedToken}
                inputDenomination={primaryDisplay.denomination}
                primaryDisplay={primaryDisplay}
              />
            )}

            {
              // !useAltLayout &&
              isAmountFocused && (
                <AcceptButtonSendPage
                  decodeSendAddress={decodeSendAddress}
                  errorMessageNavigation={errorMessageNavigation}
                  btcAdress={btcAdress}
                  paymentInfo={paymentInfo}
                  convertedSendAmount={convertedSendAmount}
                  paymentDescription={combinedPaymentDescription}
                  setPaymentInfo={setPaymentInfo}
                  setLoadingMessage={setLoadingMessage}
                  fromPage={fromPage}
                  sparkInformation={sparkInformation}
                  seletctedToken={seletctedToken}
                  useAltLayout={false} //will be useAltLayout in future
                  sendWebViewRequest={sendWebViewRequest}
                  globalContactsInformation={globalContactsInformation}
                  canUseFastPay={canUseFastPay}
                  selectedPaymentMethod={resolvedPaymentMethod}
                  bitcoinBalance={bitcoinBalance}
                  dollarBalanceSat={dollarBalanceSat}
                  isDecoding={isDecoding || isEstimatingFee}
                  poolInfoRef={poolInfoRef}
                  swapLimits={swapLimits}
                  min_usd_swap_amount={min_usd_swap_amount}
                  inputDenomination={primaryDisplay.denomination}
                  paymentValidation={paymentValidation}
                  setDidSelectPaymentMethod={setDidSelectPaymentMethod}
                  conversionFiatStats={conversionFiatStats}
                  primaryDisplay={primaryDisplay}
                  enteredPaymentInfo={enteredPaymentInfo}
                  enteredDisplaySnapshot={buildAmountSnapshot(sendingAmount)}
                />
              )
            }
          </>
        )}

        {/* SELECT_PAYMENT method state - show button to take user to select half modal */}
        {uiState === 'CHOOSE_METHOD' && (
          <CustomButton
            buttonStyles={{
              ...CENTER,
              width: INSET_WINDOW_WIDTH,
              opacity: paymentValidation.isValid ? 1 : HIDDEN_OPACITY,
            }}
            actionFunction={() => handleSelectPaymentMethod(true)}
            textContent={t('constants.review')}
          />
        )}

        {/* SWAP_RATES_CHANGED — primary CTA to re-enter amount */}
        {uiState === 'SWAP_RATES_CHANGED' && (
          <CustomButton
            buttonStyles={{
              width: INSET_WINDOW_WIDTH,
              ...CENTER,
            }}
            actionFunction={handleRateChangedReset}
            textContent={t(
              'wallet.sendPages.sendPaymentScreen.swapRatesChangedButton',
            )}
          />
        )}

        {/* CONFIRM_PAYMENT State - Show swipe button or progress animation */}
        {uiState === 'CONFIRM_PAYMENT' && (
          <View style={styles.buttonContainer}>
            {showProgressAnimation || isUsingFastPay ? (
              <SliderProgressAnimation
                ref={progressAnimationRef}
                isVisible={showProgressAnimation || isUsingFastPay}
                textColor={COLORS.darkModeText}
                backgroundColor={
                  theme && darkModeType ? backgroundOffset : COLORS.primary
                }
                width={0.95}
              />
            ) : (
              <SwipeButtonNew
                onSwipeSuccess={sendPayment}
                width={0.85}
                resetAfterSuccessAnimDuration={true}
                // shouldAnimateViewOnSuccess={true}
                shouldResetAfterSuccess={!canSendPayment}
                // shouldDisplaySuccessState={isSendingPayment}
                containerStyles={{
                  opacity: canSendPayment ? 1 : HIDDEN_OPACITY,
                }}
                thumbIconStyles={{
                  backgroundColor:
                    theme && darkModeType ? backgroundOffset : backgroundColor,
                  borderColor:
                    theme && darkModeType ? backgroundOffset : backgroundColor,
                }}
                railStyles={{
                  backgroundColor:
                    theme && darkModeType ? backgroundOffset : backgroundColor,
                  borderColor:
                    theme && darkModeType ? backgroundOffset : backgroundColor,
                }}
              />
            )}
          </View>
        )}
      </View>

      {/* Emoji bar for description input */}
      {!isAmountFocused && uiState === 'EDIT_AMOUNT' && (
        <EmojiQuickBar
          description={combinedPaymentDescription}
          onEmojiSelect={handleEmoji}
        />
      )}
    </CustomKeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  replacementContainer: {
    flexGrow: 1,
    width: WINDOWWIDTH,
    ...CENTER,
  },
  sectionTitle: {
    fontSize: SIZES.medium,
    opacity: HIDDEN_OPACITY,
    textAlign: 'center',
    marginBottom: CONTENT_KEYBOARD_OFFSET,
  },
  balanceScrollContainer: {
    flexGrow: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingVertical: 10,
  },
  maxAndAcceptContainer: {
    width: INSET_WINDOW_WIDTH,
    flexDirection: 'row',
    alignItems: 'center',
    marginTop: 10,
    ...CENTER,
  },
  buttonContainer: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  selectTokenText: {
    textDecorationLine: 'underline',
    paddingVertical: 10,
    textAlign: 'center',
  },
  selectMethodButton: {
    width: INSET_WINDOW_WIDTH,
    marginBottom: 20,
  },
});
