/* eslint-disable @typescript-eslint/indent */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
import type {
  DonationSettings,
  TCheckoutSession,
  TLineItemExpanded,
  TPaymentCurrency,
  TPaymentIntent,
  TPaymentMethodExpanded,
} from '@blocklet/payment-types';
import { HelpOutline } from '@mui/icons-material';
import { Box, Divider, Fade, Grow, Stack, Tooltip, Typography, Collapse, IconButton } from '@mui/material';
import type { IconButtonProps } from '@mui/material';
import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
import { useRequest, useSetState } from 'ahooks';
import noop from 'lodash/noop';
import useBus from 'use-bus';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { styled } from '@mui/material/styles';
import { useEffect, useMemo, useRef } from 'react';
import Status from '../components/status';
import api from '../libs/api';
import {
  formatAmount,
  formatCheckoutHeadlines,
  getPriceUintAmountByCurrency,
  formatDynamicPrice,
  findCurrency,
  formatError,
} from '../libs/util';
import ProductDonation from './product-donation';
import ProductItem from './product-item';
import Livemode from '../components/livemode';
import { usePaymentContext } from '../contexts/payment';
import { useMobile } from '../hooks/mobile';
import { useDynamicPricing, type LiveRateInfo, type LiveQuoteSnapshot } from '../hooks/dynamic-pricing';
import LoadingButton from '../components/loading-button';
import DynamicPricingUnavailable from '../components/dynamic-pricing-unavailable';
import PromotionSection from './summary-section/promotion-section';
import TotalSection from './summary-section/total-section';
import type { SlippageConfigValue } from '../components/slippage-config';

interface ExpandMoreProps extends IconButtonProps {
  expand: boolean;
}

const ExpandMore = styled((props: ExpandMoreProps) => {
  const { expand, ...other } = props;
  return <IconButton {...other} />;
})(({ theme, expand }) => ({
  transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
  marginLeft: 'auto',
  transition: theme.transitions.create('transform', {
    duration: theme.transitions.duration.shortest,
  }),
}));

type Props = {
  items: TLineItemExpanded[];
  currency: TPaymentCurrency;
  trialInDays: number;
  trialEnd?: number;
  billingThreshold: number;
  showStaking?: boolean;
  onUpsell?: Function;
  onDownsell?: Function;
  onQuantityChange?: Function;
  onChangeAmount?: Function;
  onApplyCrossSell?: Function;
  onCancelCrossSell?: Function;
  checkoutSessionId?: string;
  crossSellBehavior?: string;
  donationSettings?: DonationSettings;
  action?: string;
  completed?: boolean;
  checkoutSession?: TCheckoutSession;
  paymentIntent?: TPaymentIntent | null;
  onPromotionUpdate?: () => void;
  paymentMethods?: TPaymentMethodExpanded[];
  showFeatures?: boolean;
  rateUnavailable?: boolean;
  rateError?: string;
  isRateLoading?: boolean; // Loading state for skeleton display during currency switch
  onQuoteExpired?: (forceRefresh?: boolean) => void;
  onRefreshRate?: () => Promise<void>;
  onSlippageChange?: (slippageConfig: SlippageConfigValue) => void;
  slippageConfig?: SlippageConfigValue;
  liveRate?: LiveRateInfo;
  liveQuoteSnapshot?: LiveQuoteSnapshot;
  isStripePayment?: boolean;
  isSubscription?: boolean;
};

async function fetchCrossSell(id: string, skipError = true) {
  try {
    const { data } = await api.get(`/api/checkout-sessions/${id}/cross-sell?skipError=${skipError}`);
    if (!data.error) {
      return data;
    }
    return null;
  } catch (err) {
    return null;
  }
}

function getStakingSetup(items: TLineItemExpanded[], currency: TPaymentCurrency, billingThreshold = 0) {
  const staking = {
    licensed: new BN(0),
    metered: new BN(0),
  };

  const recurringItems = items
    .map((x) => x.upsell_price || x.price)
    .filter((x) => x.type === 'recurring' && x.recurring);

  if (recurringItems.length > 0) {
    if (+billingThreshold) {
      return fromTokenToUnit(billingThreshold, currency.decimal).toString();
    }

    items.forEach((x) => {
      const price = x.upsell_price || x.price;
      const unit = getPriceUintAmountByCurrency(price, currency);
      const amount = new BN(unit).mul(new BN(x.quantity));
      if (price.type === 'recurring' && price.recurring) {
        if (price.recurring.usage_type === 'licensed') {
          staking.licensed = staking.licensed.add(amount);
        }
        if (price.recurring.usage_type === 'metered') {
          staking.metered = staking.metered.add(amount);
        }
      }
    });

    return staking.licensed.add(staking.metered).toString();
  }

  return '0';
}

export default function PaymentSummary({
  items,
  currency,
  trialInDays,
  billingThreshold,
  onUpsell = noop,
  onDownsell = noop,
  onQuantityChange = noop,
  onApplyCrossSell = noop,
  onCancelCrossSell = noop,
  onChangeAmount = noop,
  checkoutSessionId = '',
  crossSellBehavior = '',
  showStaking = false,
  donationSettings = undefined,
  action = '',
  trialEnd = 0,
  completed = false,
  checkoutSession = undefined,
  paymentIntent = undefined,
  paymentMethods = [],
  onPromotionUpdate = noop,
  showFeatures = false,
  rateUnavailable = false,
  isRateLoading = false,
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  rateError: _rateError = undefined, // Technical errors are logged but not displayed to users
  onQuoteExpired = undefined,
  onRefreshRate = undefined,
  onSlippageChange = undefined,
  slippageConfig: slippageConfigProp = undefined,
  liveRate = undefined,
  liveQuoteSnapshot = undefined,
  isStripePayment = false,
  isSubscription: isSubscriptionProp = undefined,
  ...rest
}: Props) {
  const { t, locale } = useLocaleContext();
  const { isMobile } = useMobile();
  const { paymentState, ...settings } = usePaymentContext();
  const [state, setState] = useSetState({ loading: false, shake: false, expanded: items?.length < 3 });
  const { data, runAsync } = useRequest((skipError) =>
    checkoutSessionId ? fetchCrossSell(checkoutSessionId, skipError) : Promise.resolve(null)
  );

  // Discounts and promotion codes
  const sessionDiscounts = (checkoutSession as any)?.discounts || [];
  const allowPromotionCodes = !!checkoutSession?.allow_promotion_codes;
  const hasDiscounts = sessionDiscounts?.length > 0;

  // Resolve discount currency
  const discountCurrency =
    paymentMethods && checkoutSession
      ? (findCurrency(
          paymentMethods as TPaymentMethodExpanded[],
          hasDiscounts ? checkoutSession?.currency_id || currency.id : (currency.id as string)
        ) as TPaymentCurrency) || settings.settings?.baseCurrency
      : currency;
  const slippageConfig = slippageConfigProp ?? (checkoutSession as any)?.metadata?.slippage;

  // Use the dynamic pricing hook for all rate-related calculations
  const {
    hasDynamicPricing,
    isPriceLocked,
    quoteMeta,
    rateInfo,
    quoteLockedAt,
    currentSlippagePercent,
    rateDisplay,
    calculatedTokenAmount,
    calculatedDiscountAmount,
    calculateUsdDisplay,
    buildQuoteDetailRows,
  } = useDynamicPricing({
    items,
    currency: discountCurrency,
    liveRate,
    liveQuoteSnapshot,
    checkoutSession,
    paymentIntent,
    locale,
    isStripePayment,
    isSubscription: isSubscriptionProp,
    slippageConfig,
    trialInDays,
    trialEnd,
    discounts: sessionDiscounts,
  });

  // Headlines and amount calculations
  const headlines = formatCheckoutHeadlines(items, discountCurrency, { trialEnd, trialInDays }, locale, {
    exchangeRate: rateInfo.exchangeRate,
  });
  const staking = showStaking ? getStakingSetup(items, discountCurrency, billingThreshold) : '0';

  // For Stripe payments, always use standard formatting regardless of dynamic pricing
  // This prevents calculation errors when switching from crypto to fiat payments
  const effectiveHasDynamicPricing = hasDynamicPricing && !isStripePayment;

  // Check if this is a trial scenario: actualAmount is '0' AND it's a subscription
  // Only subscriptions (recurring items) have trials - one_time products should still be charged
  const hasRecurringItems = items.some((x) => (x.upsell_price || x.price)?.type === 'recurring');
  const isTrialScenario = headlines.actualAmount === '0' && hasRecurringItems;

  const headlineAmountDisplay = useMemo(() => {
    // For Stripe payments, use standard formatting regardless of dynamic pricing
    if (!effectiveHasDynamicPricing) {
      return headlines.amount;
    }
    // For trial scenarios, use the formatted trial amount (e.g., "Free 7-day trial")
    if (isTrialScenario || !headlines.amount.includes(discountCurrency.symbol)) {
      return headlines.amount;
    }
    if (calculatedTokenAmount) {
      const displayAmount = fromUnitToToken(calculatedTokenAmount, discountCurrency?.decimal);
      const formatted = formatDynamicPrice(displayAmount, true, 6);
      return `${formatted} ${discountCurrency.symbol}`;
    }
    const formatted = formatDynamicPrice(headlines.actualAmount, true, 6);
    return `${formatted} ${discountCurrency.symbol}`;
  }, [
    headlines.amount,
    headlines.actualAmount,
    discountCurrency.symbol,
    discountCurrency?.decimal,
    effectiveHasDynamicPricing,
    calculatedTokenAmount,
    isTrialScenario,
  ]);

  // Amount calculations - wrap discountAmount in useMemo to avoid dependency warning
  const discountAmount = useMemo(
    () => new BN(checkoutSession?.total_details?.amount_discount || '0'),
    [checkoutSession?.total_details?.amount_discount]
  );
  const subtotalAmountUnit = new BN(fromTokenToUnit(headlines.actualAmount, discountCurrency?.decimal))
    .add(new BN(staking))
    .toString();
  const subtotalAmount = fromUnitToToken(subtotalAmountUnit, discountCurrency?.decimal);
  const totalAmountUnit = new BN(subtotalAmountUnit).sub(discountAmount).toString();
  const totalAmountValue = fromUnitToToken(totalAmountUnit, discountCurrency?.decimal);

  // Format displays - for dynamic pricing, include staking in the calculated total
  // For trial scenarios, don't add calculatedTokenAmount since payment amount is 0
  const subtotalDisplay = useMemo(() => {
    if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
      const dynamicSubtotalUnit = new BN(calculatedTokenAmount).add(new BN(staking)).toString();
      const displayAmount = fromUnitToToken(dynamicSubtotalUnit, discountCurrency?.decimal);
      return formatDynamicPrice(displayAmount, true, 6);
    }
    return formatDynamicPrice(subtotalAmount, effectiveHasDynamicPricing, 6);
  }, [
    effectiveHasDynamicPricing,
    calculatedTokenAmount,
    staking,
    discountCurrency?.decimal,
    subtotalAmount,
    isTrialScenario,
  ]);

  const totalAmountDisplay = useMemo(() => {
    // For trial scenarios, don't add calculatedTokenAmount since payment amount is 0
    if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
      // Use calculatedDiscountAmount (frontend) instead of discountAmount (backend)
      // Backend discountAmount is stale when exchange rate changes
      const effectiveDiscount = calculatedDiscountAmount ? new BN(calculatedDiscountAmount) : discountAmount;
      const dynamicTotalUnit = new BN(calculatedTokenAmount).add(new BN(staking)).sub(effectiveDiscount).toString();
      const displayAmount = fromUnitToToken(dynamicTotalUnit, discountCurrency?.decimal);
      const numericValue = Number(displayAmount);
      if (Number.isFinite(numericValue) && numericValue >= 0) {
        return formatDynamicPrice(displayAmount, true, 6);
      }
    }

    // For Stripe payments: use calculatedDiscountAmount when backend discountAmount is 0 or stale
    // This ensures correct total when discount is applied but backend hasn't recalculated
    if (isStripePayment && calculatedDiscountAmount && !isTrialScenario) {
      const effectiveDiscount = new BN(calculatedDiscountAmount);
      const adjustedTotalUnit = new BN(subtotalAmountUnit).sub(effectiveDiscount).toString();
      const displayAmount = fromUnitToToken(adjustedTotalUnit, discountCurrency?.decimal);
      const numericValue = Number(displayAmount);
      if (Number.isFinite(numericValue) && numericValue >= 0) {
        return formatDynamicPrice(displayAmount, false, 6);
      }
    }

    return formatDynamicPrice(totalAmountValue, effectiveHasDynamicPricing, 6);
  }, [
    effectiveHasDynamicPricing,
    calculatedTokenAmount,
    staking,
    discountAmount,
    calculatedDiscountAmount,
    discountCurrency?.decimal,
    totalAmountValue,
    isTrialScenario,
    isStripePayment,
    subtotalAmountUnit,
  ]);
  const totalAmountText = totalAmountDisplay === '—' ? '—' : `${totalAmountDisplay} ${discountCurrency.symbol}`;

  // Fix: Use dynamically calculated total for USD display, not static totalAmountValue
  // For Stripe payments, no USD equivalent display is needed since it's already USD
  // For trial scenarios, don't add calculatedTokenAmount since payment amount is 0
  const totalUsdDisplay = useMemo(() => {
    if (effectiveHasDynamicPricing && calculatedTokenAmount && !isTrialScenario) {
      // Use calculatedDiscountAmount (frontend) instead of discountAmount (backend)
      const effectiveDiscount = calculatedDiscountAmount ? new BN(calculatedDiscountAmount) : discountAmount;
      const dynamicTotalUnit = new BN(calculatedTokenAmount).add(new BN(staking)).sub(effectiveDiscount).toString();
      const dynamicTotalToken = fromUnitToToken(dynamicTotalUnit, discountCurrency?.decimal);
      return calculateUsdDisplay(dynamicTotalToken);
    }
    return calculateUsdDisplay(totalAmountValue);
  }, [
    effectiveHasDynamicPricing,
    calculatedTokenAmount,
    staking,
    discountAmount,
    calculatedDiscountAmount,
    discountCurrency?.decimal,
    totalAmountValue,
    calculateUsdDisplay,
    isTrialScenario,
  ]);

  const quoteDetailRows = buildQuoteDetailRows(t);
  const isSubscription =
    isSubscriptionProp ?? (checkoutSession?.mode === 'subscription' || checkoutSession?.mode === 'setup');

  // Promotion handlers
  const handlePromotionUpdate = () => {
    onPromotionUpdate?.();
  };

  const handleRemovePromotion = async (sessionId: string) => {
    if (paymentState.paying || paymentState.stripePaying) {
      return;
    }
    try {
      await api.delete(`/api/checkout-sessions/${sessionId}/remove-promotion`);
      onPromotionUpdate?.();
    } catch (err: any) {
      console.error('Failed to remove promotion code:', err);
    }
  };

  // Quote expiry handling (backward compatibility - Final Freeze deprecates this)
  const expiredHandledRef = useRef(false);

  useEffect(() => {
    if (completed || expiredHandledRef.current) {
      return;
    }
    // In Final Freeze, there's no quote during preview, so no expiry check needed
    if (!liveQuoteSnapshot?.expires_at && !quoteMeta?.expiresAt) {
      return;
    }
    const currentTime = Math.floor(Date.now() / 1000);
    const effectiveExpiresAt = liveQuoteSnapshot?.expires_at ?? quoteMeta?.expiresAt;
    const quoteRemaining = effectiveExpiresAt ? Math.max(0, effectiveExpiresAt - currentTime) : 0;
    const lockRemaining = quoteLockedAt ? Math.max(0, quoteLockedAt + 180 - currentTime) : 0;
    const hasExpiry = !!effectiveExpiresAt;

    const lockActive = lockRemaining > 0;
    if (hasExpiry && !lockActive && quoteRemaining <= 0) {
      expiredHandledRef.current = true;
      onQuoteExpired?.();
    }
  }, [liveQuoteSnapshot?.expires_at, quoteMeta?.expiresAt, quoteLockedAt, completed, onQuoteExpired]);

  // Slippage handler
  const handleSlippageChange = async (newSlippageConfig: SlippageConfigValue) => {
    if (!onSlippageChange) {
      return;
    }
    if (!checkoutSessionId) {
      onSlippageChange(newSlippageConfig);
      return;
    }
    try {
      await api.put(`/api/checkout-sessions/${checkoutSessionId}/slippage`, {
        slippage_config: newSlippageConfig,
      });
      onSlippageChange(newSlippageConfig);
      if (onQuoteExpired) {
        await onQuoteExpired(true);
      }
    } catch (err: any) {
      console.error('Failed to update slippage', err);
      Toast.error(err.response?.data?.error || formatError(err));
    }
  };

  // Cross-sell event handling
  useBus(
    'error.REQUIRE_CROSS_SELL',
    () => {
      setState({ shake: true });
      setTimeout(() => {
        setState({ shake: false });
      }, 1000);
    },
    []
  );

  // Product action handlers
  const handleUpsell = async (from: string, to: string) => {
    await onUpsell!(from, to);
    runAsync(false);
  };

  const handleQuantityChange = async (itemId: string, quantity: number) => {
    await onQuantityChange!(itemId, quantity);
    runAsync(false);
  };

  const handleDownsell = async (from: string) => {
    await onDownsell!(from);
    runAsync(false);
  };

  const handleApplyCrossSell = async () => {
    if (data) {
      try {
        setState({ loading: true });
        await onApplyCrossSell!(data.id);
      } catch (err) {
        console.error(err);
      } finally {
        setState({ loading: false });
      }
    }
  };

  const handleCancelCrossSell = async () => {
    try {
      setState({ loading: true });
      await onCancelCrossSell!();
    } catch (err) {
      console.error(err);
    } finally {
      setState({ loading: false });
    }
  };

  const hasSubTotal = +staking > 0 || allowPromotionCodes;

  // Product list component
  const ProductCardList = (
    <Stack
      className="cko-product-list"
      sx={{
        flex: '0 1 auto',
        overflow: 'auto',
      }}>
      <Stack spacing={{ xs: 1, sm: 2 }}>
        {items.map((x: TLineItemExpanded) =>
          x.price?.custom_unit_amount && onChangeAmount && donationSettings ? (
            <ProductDonation
              key={`${x.price_id}-${discountCurrency.id}`}
              item={x}
              settings={donationSettings}
              onChange={onChangeAmount}
              currency={discountCurrency}
            />
          ) : (
            <ProductItem
              key={`${x.price_id}-${discountCurrency.id}`}
              item={x}
              items={items}
              trialInDays={trialInDays}
              trialEnd={trialEnd}
              currency={discountCurrency}
              exchangeRate={rateInfo.exchangeRate}
              isStripePayment={isStripePayment}
              isPriceLocked={isPriceLocked}
              isRateLoading={isRateLoading}
              onUpsell={handleUpsell}
              onDownsell={handleDownsell}
              adjustableQuantity={x.adjustable_quantity}
              completed={completed}
              showFeatures={showFeatures}
              onQuantityChange={handleQuantityChange}
              discounts={sessionDiscounts}
              calculatedDiscountAmount={
                calculatedDiscountAmount || (isStripePayment ? discountAmount.toString() : null)
              }>
              {x.cross_sell && (
                <Stack
                  direction="row"
                  sx={{
                    alignItems: 'center',
                    justifyContent: 'space-between',
                    width: 1,
                  }}>
                  <Typography />
                  <LoadingButton
                    size="small"
                    loadingPosition="end"
                    endIcon={null}
                    color="error"
                    variant="text"
                    loading={state.loading}
                    onClick={handleCancelCrossSell}>
                    {t('payment.checkout.cross_sell.remove')}
                  </LoadingButton>
                </Stack>
              )}
            </ProductItem>
          )
        )}
      </Stack>
      {data && items.some((x) => x.price_id === data.id) === false && (
        <Grow in>
          <Stack sx={{ mt: 1 }}>
            <ProductItem
              item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
              items={items}
              trialInDays={trialInDays}
              currency={discountCurrency}
              trialEnd={trialEnd}
              exchangeRate={rateInfo.exchangeRate}
              isStripePayment={isStripePayment}
              isPriceLocked={isPriceLocked}
              isRateLoading={isRateLoading}
              onUpsell={noop}
              onDownsell={noop}>
              <Stack
                direction="row"
                sx={{
                  alignItems: 'center',
                  justifyContent: 'space-between',
                  width: 1,
                }}>
                <Typography>
                  {crossSellBehavior === 'required' && (
                    <Status label={t('payment.checkout.required')} color="info" variant="outlined" sx={{ mr: 1 }} />
                  )}
                </Typography>
                <LoadingButton
                  size="small"
                  loadingPosition="end"
                  endIcon={null}
                  color={crossSellBehavior === 'required' ? 'info' : 'info'}
                  variant={crossSellBehavior === 'required' ? 'text' : 'text'}
                  loading={state.loading}
                  onClick={handleApplyCrossSell}>
                  {t('payment.checkout.cross_sell.add')}
                </LoadingButton>
              </Stack>
            </ProductItem>
          </Stack>
        </Grow>
      )}
    </Stack>
  );

  if (!discountCurrency || !items?.length) {
    return null;
  }

  return (
    <Fade in>
      <Stack className="cko-product" direction="column" {...rest}>
        {/* Header */}
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            mb: 2.5,
          }}>
          <Typography
            title={t('payment.checkout.orderSummary')}
            sx={{
              color: 'text.primary',
              fontSize: { xs: '18px', md: '24px' },
              fontWeight: '700',
              lineHeight: '32px',
            }}>
            {action || t('payment.checkout.orderSummary')}
          </Typography>
          {!settings.livemode && <Livemode />}
        </Box>

        {/* Dynamic pricing unavailable warning - hide for Stripe payments since no exchange rate needed */}
        {effectiveHasDynamicPricing && rateUnavailable && (
          <DynamicPricingUnavailable sx={{ mb: 2 }} onRetry={onRefreshRate} />
        )}

        {/* Product list (collapsible on mobile) */}
        {isMobile && !donationSettings ? (
          <>
            <Stack
              onClick={() => setState({ expanded: !state.expanded })}
              sx={{
                justifyContent: 'space-between',
                flexDirection: 'row',
                alignItems: 'center',
                mb: 1.5,
              }}>
              <Typography>{t('payment.checkout.productListTotal', { total: items.length })}</Typography>
              <ExpandMore expand={state.expanded} aria-expanded={state.expanded} aria-label="show more">
                <ExpandMoreIcon />
              </ExpandMore>
            </Stack>
            <Collapse in={state.expanded || !isMobile} timeout="auto" unmountOnExit>
              {ProductCardList}
            </Collapse>
          </>
        ) : (
          ProductCardList
        )}

        <Divider sx={{ mt: 2.5, mb: 2.5 }} />

        {/* Staking section */}
        {+staking > 0 && (
          <Stack spacing={1}>
            <Stack direction="row" spacing={1} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
              <Stack direction="row" spacing={0.5} sx={{ alignItems: 'center' }}>
                <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.paymentRequired')}</Typography>
                <Tooltip title={t('payment.checkout.stakingConfirm')} placement="top" sx={{ maxWidth: '150px' }}>
                  <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
                </Tooltip>
              </Stack>
              <Typography>{headlineAmountDisplay}</Typography>
            </Stack>
            <Stack direction="row" spacing={1} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
              <Stack direction="row" spacing={0.5} sx={{ alignItems: 'center' }}>
                <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.staking.title')}</Typography>
                <Tooltip title={t('payment.checkout.staking.tooltip')} placement="top" sx={{ maxWidth: '150px' }}>
                  <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
                </Tooltip>
              </Stack>
              <Typography>
                {formatAmount(staking, discountCurrency.decimal)} {discountCurrency.symbol}
              </Typography>
            </Stack>
          </Stack>
        )}

        {/* Subtotal row */}
        {(allowPromotionCodes || hasDiscounts) && (
          <Stack
            direction="row"
            spacing={1}
            sx={{
              justifyContent: 'space-between',
              alignItems: 'center',
              ...(+staking > 0 && {
                borderTop: '1px solid',
                borderColor: 'divider',
                pt: 1,
                mt: 1,
              }),
            }}>
            <Typography className="base-label">{t('common.subtotal')}</Typography>
            <Typography>
              {subtotalDisplay} {discountCurrency.symbol}
            </Typography>
          </Stack>
        )}

        {/* Promotion section */}
        {/* For Stripe payments, use total_details.amount_discount (backend calculated) */}
        {/* For dynamic pricing, use calculatedDiscountAmount (frontend calculated based on rate) */}
        <PromotionSection
          checkoutSessionId={checkoutSession?.id || checkoutSessionId}
          currency={discountCurrency}
          currencyId={currency.id}
          discounts={sessionDiscounts}
          allowPromotionCodes={allowPromotionCodes}
          completed={completed}
          disabled={paymentState.paying || paymentState.stripePaying}
          onPromotionUpdate={handlePromotionUpdate}
          onRemovePromotion={handleRemovePromotion}
          calculatedDiscountAmount={calculatedDiscountAmount || (isStripePayment ? discountAmount.toString() : null)}
          isRateLoading={isRateLoading}
        />

        {hasSubTotal && <Divider sx={{ my: 1 }} />}

        {/* Total section */}
        <TotalSection
          totalAmountText={totalAmountText}
          totalUsdDisplay={totalUsdDisplay}
          currency={discountCurrency}
          hasDynamicPricing={hasDynamicPricing}
          rateDisplay={rateDisplay}
          rateInfo={rateInfo}
          quoteDetailRows={quoteDetailRows}
          currentSlippagePercent={currentSlippagePercent}
          slippageConfig={slippageConfig}
          isPriceLocked={isPriceLocked}
          isSubscription={isSubscription}
          completed={completed}
          onSlippageChange={onSlippageChange ? handleSlippageChange : undefined}
          isStripePayment={isStripePayment}
          isRateLoading={isRateLoading}
          thenInfo={headlines.thenValue && headlines.showThen ? headlines.thenValue : undefined}
        />
      </Stack>
    </Fade>
  );
}
