import { useState, useMemo, useEffect, useRef, useCallback } from 'react';
import { Box, IconButton, Typography, InputBase, Stack } from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import AccessTimeOutlinedIcon from '@mui/icons-material/AccessTimeOutlined';
import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined';
import { useRequest } from 'ahooks';
import { BN, fromTokenToUnit } from '@ocap/util';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
import {
  useCheckoutStatus,
  useLineItems,
  useSessionContext,
  useProduct,
  useExchangeRate,
  useSlippage,
  usePaymentMethodContext,
  useSubmitFeature,
} from '@blocklet/payment-react-headless';

import { usePaymentContext } from '../../../contexts/payment';
import api from '../../../libs/api';
import { formatNumber, formatBNStr, formatCreditForCheckout, formatCreditAmount } from '../../../libs/util';
import { tSafe } from '../../utils/format';
import ScenarioBadge from '../../components/shared/scenario-badge';
import ExchangeRateFooter from '../../components/shared/exchange-rate-footer';

export default function CreditTopupPanel() {
  const { t, locale } = useLocaleContext();
  const { session, sessionData } = useSessionContext();
  const { livemode } = useCheckoutStatus();
  const { product } = useProduct();
  const { currency, isStripe } = usePaymentMethodContext();
  const lineItems = useLineItems();
  const rate = useExchangeRate();
  const slippage = useSlippage();
  const { locked: configLocked } = useSubmitFeature();

  const item = lineItems.items[0];
  const activePrice: any = item ? (item as any).upsell_price || item.price : null;

  // Credit metadata
  const creditConfig = activePrice?.metadata?.credit_config;
  const creditAmount = creditConfig?.credit_amount ? Number(creditConfig.credit_amount) : 0;
  const creditCurrencyId = creditConfig?.currency_id;

  // DID session for login state and userDid; getCurrency from /api/settings (same as V1)
  const { session: didSession, getCurrency } = usePaymentContext();

  // Credit currency: use getCurrency from /api/settings — same data source as V1
  const creditCurrency = creditCurrencyId ? getCurrency(creditCurrencyId) : null;
  const userDid = didSession?.user?.did || (sessionData?.customer as any)?.did;

  const creditCurrencyDecimal = creditCurrency?.decimal;
  const creditCurrencySymbol = creditCurrency?.symbol || 'Credits';

  const currencySymbol = 'Credits';

  // Fetch meter data by meter_id from price metadata
  const meterId = activePrice?.metadata?.meter_id;
  const { data: meterData } = useRequest(
    async () => {
      if (!meterId) return null;
      try {
        const { data } = await api.get(`/api/meters/public/${meterId}`);
        return data;
      } catch {
        return null;
      }
    },
    { refreshDeps: [meterId] }
  );

  const creditName = meterData?.name || product?.name || 'Credits';

  // Credit config details
  const validDuration = creditConfig?.valid_duration_value;
  const validDurationUnit = creditConfig?.valid_duration_unit || 'days';
  const scheduleConfig = creditConfig?.schedule;
  const hasSchedule =
    scheduleConfig?.enabled && scheduleConfig?.delivery_mode && scheduleConfig.delivery_mode !== 'invoice';
  const hasExpiry = validDuration && validDuration > 0;

  // Step size: each +/- changes by one pack's worth of credits
  const step = Math.max(creditAmount, 1);

  // Adjustable quantity config
  const adjustableQty = item?.adjustable_quantity;
  const canAdjust = adjustableQty?.enabled !== false;
  const minQuantity = Math.max(adjustableQty?.minimum || 1, 1);
  const quantityAvailable = Math.min(
    activePrice?.quantity_limit_per_checkout ?? Infinity,
    activePrice?.quantity_available ?? Infinity
  );
  const maxQuantity = quantityAvailable
    ? Math.min(adjustableQty?.maximum || Infinity, quantityAvailable)
    : adjustableQty?.maximum || Infinity;
  const { data: pendingAmount } = useRequest(
    async () => {
      // Wait for credit currency decimal before fetching — calculations depend on correct decimal
      if (!creditConfig || !userDid || !creditCurrencyId || creditCurrencyDecimal == null) return null;
      try {
        const { data } = await api.get('/api/meter-events/pending-amount', {
          params: { customer_id: userDid, currency_id: creditCurrencyId },
        });
        return data?.[creditCurrencyId];
      } catch {
        return null;
      }
    },
    { refreshDeps: [creditConfig, userDid, creditCurrencyId, creditCurrencyDecimal] }
  );

  // Min quantity needed to cover pending
  const minQtyForPending = useMemo(() => {
    if (!pendingAmount || !creditAmount || creditAmount <= 0) return null;
    const pendingBN = new BN(pendingAmount || '0');
    if (!pendingBN.gt(new BN(0))) return null;
    // creditCurrencyDecimal is guaranteed non-null here (pending fetch depends on it)
    const creditBN = fromTokenToUnit(creditAmount, creditCurrencyDecimal!);
    if (!creditBN || creditBN.isZero()) return null;
    return Math.ceil(pendingBN.mul(new BN(100)).div(creditBN).toNumber() / 100);
  }, [pendingAmount, creditAmount, creditCurrencyDecimal]);

  // Credit info description (referencing V1 formatCreditInfo)
  const hasPendingAmount = pendingAmount && new BN(pendingAmount || '0').gt(new BN(0));
  const pendingDisplayAmount = useMemo(() => {
    if (!hasPendingAmount) return '';
    // creditCurrencyDecimal is guaranteed non-null here (pending fetch depends on it)
    return formatCreditForCheckout(formatBNStr(pendingAmount!, creditCurrencyDecimal!), creditCurrencySymbol, locale);
  }, [hasPendingAmount, pendingAmount, creditCurrencyDecimal, creditCurrencySymbol, locale]);

  // Min credits needed to cover pending (for user-facing display)
  const minCreditsForPending = minQtyForPending ? minQtyForPending * step : 0;
  const minCreditsForPendingFormatted = minCreditsForPending
    ? formatCreditForCheckout(formatNumber(minCreditsForPending), creditCurrencySymbol, locale)
    : '';

  // Credit info text: schedule or product description (no fallback "Purchase X")
  const creditInfoText = useMemo(() => {
    if (hasSchedule && scheduleConfig) {
      const intervalUnit = scheduleConfig.interval_unit;
      const intervalValue = scheduleConfig.interval_value;
      let amountPerGrant: number;
      if (scheduleConfig.amount_per_grant) {
        amountPerGrant = Number(scheduleConfig.amount_per_grant);
      } else {
        amountPerGrant = creditAmount;
      }
      const formattedAmount = formatCreditAmount(formatNumber(amountPerGrant), currencySymbol);
      const intervalDisplay =
        intervalValue === 1 ? t(`common.${intervalUnit}`) : `${intervalValue} ${t(`common.${intervalUnit}s` as any)}`;
      return scheduleConfig.expire_with_next_grant
        ? t('payment.checkout.credit.schedule.withRefresh', { amount: formattedAmount, interval: intervalDisplay })
        : t('payment.checkout.credit.schedule.periodic', { amount: formattedAmount, interval: intervalDisplay });
    }
    return '';
  }, [creditAmount, currencySymbol, hasSchedule, scheduleConfig, t]);

  // Validity text: "Credits are valid for X days after purchase."
  const validityText = useMemo(() => {
    if (!hasExpiry) return '';
    return t('payment.checkout.creditTopup.validFor', {
      duration: validDuration,
      unit: t(`common.${validDurationUnit}`),
    });
  }, [hasExpiry, validDuration, validDurationUnit, t]);

  const hasSubtitle = !!creditInfoText;

  // ── State: user inputs desired credits, we compute packs ──
  const currentQty = item?.quantity || 1;
  const [localQty, setLocalQty] = useState(currentQty); // pack quantity (source of truth for API)
  const [desiredCredits, setDesiredCredits] = useState(currentQty * step); // what user sees/types
  const [isEditing, setIsEditing] = useState(false);
  const [editValue, setEditValue] = useState('');
  const inputRef = useRef<HTMLInputElement>(null);

  // Sync when item quantity changes from backend (skip if locked or already completed)
  useEffect(() => {
    if (configLocked || session?.status === 'complete') return;
    if (item?.quantity && item.quantity !== localQty) {
      setLocalQty(item.quantity);
      setDesiredCredits(item.quantity * step);
    }
  }, [item?.quantity]); // eslint-disable-line react-hooks/exhaustive-deps

  // Enforce min quantity for pending — only once on initial load.
  // After user confirms quantity (e.g. clicks "Connect and Pay"), don't override their choice.
  const pendingEnforcedRef = useRef(false);
  useEffect(() => {
    if (configLocked || session?.status === 'complete') return;
    if (pendingEnforcedRef.current) return;
    if (minQtyForPending && minQtyForPending > localQty) {
      pendingEnforcedRef.current = true;
      const newQty = Math.min(Math.max(minQtyForPending, minQuantity), maxQuantity);
      setLocalQty(newQty);
      setDesiredCredits(newQty * step);
      if (item) lineItems.updateQuantity(item.price_id, newQty);
    }
  }, [minQtyForPending]); // eslint-disable-line react-hooks/exhaustive-deps

  // Max credits = maxQuantity packs * credits per pack
  const maxCredits = maxQuantity * step;
  const minCredits = minQuantity * step;

  // Debounce API calls — UI updates immediately, API fires after 400ms idle
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  useEffect(
    () => () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    },
    []
  );

  // Commit desired credits → compute packs → update API (debounced)
  const commitCredits = useCallback(
    (credits: number) => {
      if (credits <= 0) return;
      // Clamp credits to valid range
      const clamped = Math.max(minCredits, Math.min(maxCredits, credits));
      const packs = Math.ceil(clamped / step);
      const clampedPacks = Math.max(minQuantity, Math.min(maxQuantity, packs));
      setLocalQty(clampedPacks);
      setDesiredCredits(clamped);
      if (item) {
        if (debounceRef.current) clearTimeout(debounceRef.current);
        debounceRef.current = setTimeout(() => {
          lineItems.updateQuantity(item.price_id, clampedPacks);
        }, 400);
      }
    },
    [step, minQuantity, maxQuantity, minCredits, maxCredits, item, lineItems]
  );

  // +/- buttons: step by one pack's worth of credits
  const handleStep = useCallback(
    (delta: number) => {
      const newCredits = desiredCredits + delta * step;
      if (newCredits < step * minQuantity || Math.ceil(newCredits / step) > maxQuantity) return;
      commitCredits(newCredits);
    },
    [desiredCredits, step, minQuantity, maxQuantity, commitCredits]
  );

  // Actual credits user will receive (always >= desired, rounded up to whole packs)
  const actualPacks = Math.max(minQuantity, Math.min(maxQuantity, Math.ceil(desiredCredits / step)));
  const actualCredits = actualPacks * step;
  const actualCreditsFormatted = formatNumber(actualCredits, 6, true, true);
  const desiredCreditsFormatted = formatNumber(desiredCredits, 6, true, true);
  const showReceiveSection = canAdjust && step > 1;

  // Pre-compute pending message to avoid deep ternary in JSX
  const pendingMessage = useMemo(() => {
    if (!hasPendingAmount) return '';
    if (actualCredits >= minCreditsForPending) {
      return t('payment.checkout.creditTopup.pendingEnough', {
        pendingAmount: pendingDisplayAmount,
        availableAmount: formatCreditForCheckout(
          formatNumber(actualCredits - minCreditsForPending),
          creditCurrencySymbol,
          locale
        ),
      });
    }
    return t('payment.checkout.creditTopup.pendingWarning', {
      pendingAmount: pendingDisplayAmount,
      minCredits: minCreditsForPendingFormatted,
    });
  }, [
    hasPendingAmount,
    actualCredits,
    minCreditsForPending,
    pendingDisplayAmount,
    creditCurrencySymbol,
    locale,
    minCreditsForPendingFormatted,
    t,
  ]);

  // Editing handlers — user types desired credit amount
  const startEditing = useCallback(() => {
    if (!canAdjust) return;
    setEditValue(String(desiredCredits));
    setIsEditing(true);
    setTimeout(() => inputRef.current?.select(), 0);
  }, [canAdjust, desiredCredits]);

  const commitEdit = useCallback(() => {
    setIsEditing(false);
    const parsed = parseInt(editValue.replace(/,/g, ''), 10);
    if (!Number.isFinite(parsed) || parsed <= 0) return;
    commitCredits(parsed);
  }, [editValue, commitCredits]);

  const handleEditKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === 'Enter') commitEdit();
      else if (e.key === 'Escape') setIsEditing(false);
    },
    [commitEdit]
  );

  // ── Shared styles ──
  const numberHeight = { xs: 48, md: 72 };
  const numberFontSx = {
    fontSize: numberHeight,
    fontWeight: 800,
    lineHeight: 1,
    letterSpacing: '-0.03em',
  };
  const circleBtnSx = {
    width: { xs: 40, md: 56 },
    height: { xs: 40, md: 56 },
    borderRadius: '50%',
    bgcolor: 'background.paper',
    border: '1px solid',
    borderColor: (theme: any) => (theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.12)' : 'divider'),
    color: 'text.secondary',
    transition: 'all 0.2s ease',
    '&:hover': {
      borderColor: 'primary.main',
      color: 'primary.main',
      bgcolor: 'background.paper',
    },
    '&.Mui-disabled': {
      borderColor: (theme: any) => (theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'),
      color: (theme: any) => (theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.15)' : 'rgba(0,0,0,0.12)'),
    },
  };

  return (
    <Box
      sx={{
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
      }}>
      {/* Main content — vertically centered */}
      <Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
        {/* Badge */}
        <ScenarioBadge livemode={livemode} label={tSafe(t, 'payment.checkout.typeBadge.topup', 'TOP-UP')} />

        {/* Title: Get Credits */}
        <Typography
          sx={{
            fontWeight: 800,
            fontSize: { xs: 28, md: 48 },
            lineHeight: 1.1,
            letterSpacing: '-0.03em',
            color: 'text.primary',
            mb: { xs: 0.5, md: 1 },
          }}>
          {t('payment.checkout.creditTopup.title', { name: creditName })}
        </Typography>

        {/* Credit info (schedule/description) */}
        {hasSubtitle && (
          <Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 1, mb: { xs: 1.5, md: 2.5 } }}>
            <Typography
              sx={{ fontSize: { xs: 13, md: 15 }, fontWeight: 500, color: 'text.secondary', lineHeight: 1.5 }}>
              {creditInfoText}
            </Typography>
          </Box>
        )}

        {/* Pending/overdue warning */}
        {hasPendingAmount && (
          <Stack
            direction="row"
            alignItems="flex-start"
            spacing={1.5}
            sx={{
              mb: { xs: 1.5, md: 2.5 },
              p: { xs: 1.5, md: 2 },
              borderRadius: '12px',
              bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(255,152,0,0.12)' : 'rgba(255,152,0,0.08)'),
              border: '1px solid',
              borderColor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(255,152,0,0.25)' : 'rgba(255,152,0,0.2)'),
            }}>
            <WarningAmberIcon sx={{ fontSize: 18, color: 'warning.main', mt: 0.25, flexShrink: 0 }} />
            <Typography sx={{ fontSize: { xs: 12, md: 13 }, fontWeight: 600, lineHeight: 1.5, color: 'text.primary' }}>
              {pendingMessage}
            </Typography>
          </Stack>
        )}

        {canAdjust ? (
          <Box sx={{ display: 'flex', flexDirection: 'column', maxWidth: 480 }}>
            {/* Question label — spaced away from subtitle, close to input */}
            <Typography
              sx={{
                fontSize: { xs: 14, md: 17 },
                fontWeight: 700,
                color: 'text.secondary',
                mt: { xs: 3, md: 5 },
                mb: { xs: 2, md: 3 },
              }}>
              {t('payment.checkout.creditTopup.question', { symbol: currencySymbol })}
            </Typography>

            {/* ── Credit input with +/- ── */}
            <Box sx={{ display: 'flex', alignItems: 'center', gap: { xs: 1.5, md: 2 } }}>
              <IconButton onClick={() => handleStep(-1)} disabled={actualPacks <= minQuantity} sx={circleBtnSx}>
                <Box component="span" sx={{ fontSize: { xs: 22, md: 28 }, fontWeight: 300, lineHeight: 1, mt: '-1px' }}>
                  &#x2212;
                </Box>
              </IconButton>

              <Box
                sx={{ flex: 1, minWidth: 0, textAlign: 'center', cursor: canAdjust ? 'text' : 'default' }}
                onClick={startEditing}>
                <Box
                  sx={{
                    height: numberHeight,
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                  }}>
                  {isEditing ? (
                    <InputBase
                      inputRef={inputRef}
                      value={editValue}
                      onChange={(e) => setEditValue(e.target.value.replace(/\D/g, ''))}
                      onBlur={commitEdit}
                      onKeyDown={handleEditKeyDown}
                      autoFocus
                      inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }}
                      sx={{
                        width: '100%',
                        bgcolor: 'transparent',
                        '&.Mui-focused': { bgcolor: 'transparent' },
                        '& input': {
                          textAlign: 'center',
                          ...numberFontSx,
                          p: 0,
                          fontFamily: 'inherit',
                          bgcolor: 'transparent',
                          '&:focus': { bgcolor: 'transparent' },
                        },
                      }}
                    />
                  ) : (
                    <Typography sx={{ ...numberFontSx, color: 'text.primary', userSelect: 'none' }}>
                      {desiredCreditsFormatted}
                    </Typography>
                  )}
                </Box>
                <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 0.75, mt: 1 }}>
                  <Typography
                    sx={{
                      fontSize: { xs: 12, md: 14 },
                      fontWeight: 700,
                      color: 'text.secondary',
                      textTransform: 'uppercase',
                      letterSpacing: '0.05em',
                    }}>
                    {currencySymbol}
                  </Typography>
                </Box>
              </Box>

              <IconButton onClick={() => handleStep(1)} disabled={actualPacks >= maxQuantity} sx={circleBtnSx}>
                <Box component="span" sx={{ fontSize: { xs: 22, md: 28 }, fontWeight: 300, lineHeight: 1 }}>
                  +
                </Box>
              </IconButton>
            </Box>

            {/* Increment hint */}
            {step > 1 && (
              <Typography
                sx={{
                  fontSize: 11,
                  fontWeight: 600,
                  color: 'grey.500',
                  textTransform: 'uppercase',
                  letterSpacing: '0.08em',
                  textAlign: 'center',
                  mt: { xs: 1.5, md: 2 },
                }}>
                {t('payment.checkout.creditTopup.increment', {
                  step: formatNumber(step, 6, true, true),
                  symbol: currencySymbol,
                })}
              </Typography>
            )}

            {/* ── "You'll receive" result card — frosted glass ── */}
            {showReceiveSection && (
              <Box
                sx={{
                  display: 'flex',
                  flexDirection: 'column',
                  mt: { xs: 3, md: 4 },
                  borderRadius: '20px',
                  backdropFilter: 'blur(12px)',
                  bgcolor: (theme) =>
                    theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.08)' : 'rgba(59,130,246,0.04)',
                  border: '1px solid',
                  borderColor: (theme) =>
                    theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.18)' : 'rgba(59,130,246,0.10)',
                  boxShadow: (theme) =>
                    theme.palette.mode === 'dark'
                      ? '0 8px 32px rgba(59,130,246,0.06)'
                      : '0 8px 32px rgba(59,130,246,0.04)',
                }}>
                {/* Main content */}
                <Box sx={{ p: { xs: 2.5, md: 3.5 } }}>
                  <Typography
                    sx={{
                      fontSize: { xs: 16, md: 20 },
                      fontWeight: 700,
                      color: 'primary.main',
                      mb: 0.5,
                    }}>
                    {t('payment.checkout.creditTopup.willReceive')}
                    {': '}
                    <Box component="span" sx={{ fontWeight: 800 }}>
                      {formatCreditForCheckout(actualCreditsFormatted, currencySymbol, locale)}
                    </Box>
                  </Typography>
                  {/* Pack info line */}
                  <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mb: 0.5 }}>
                    <Inventory2OutlinedIcon sx={{ fontSize: 16, color: 'text.secondary' }} />
                    <Typography sx={{ fontSize: { xs: 12, md: 14 }, fontWeight: 600, color: 'text.secondary' }}>
                      {t('payment.checkout.creditTopup.packInfo', {
                        packs: actualPacks,
                        perPack: formatNumber(step, 6, true, true),
                      })}
                    </Typography>
                  </Box>
                  {/* Auto match hint */}
                  <Typography
                    sx={{
                      fontSize: { xs: 12, md: 13 },
                      fontWeight: 500,
                      color: 'grey.500',
                    }}>
                    {t('payment.checkout.creditTopup.autoMatch')}
                  </Typography>
                </Box>
                {/* Validity footer */}
                {validityText && (
                  <Box
                    sx={{
                      display: 'flex',
                      alignItems: 'center',
                      gap: 0.75,
                      px: { xs: 2.5, md: 3.5 },
                      py: { xs: 1.5, md: 2 },
                      borderTop: '1px solid',
                      borderColor: (theme) =>
                        theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.15)' : 'rgba(59,130,246,0.08)',
                    }}>
                    <AccessTimeOutlinedIcon sx={{ fontSize: 14, color: 'grey.500' }} />
                    <Typography
                      sx={{
                        fontSize: { xs: 12, md: 13 },
                        fontWeight: 500,
                        color: 'grey.500',
                      }}>
                      {validityText}
                    </Typography>
                  </Box>
                )}
              </Box>
            )}

            {/* Validity hint — shown below input when no receive box */}
            {!showReceiveSection && validityText && (
              <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: { xs: 2.5, md: 3.5 } }}>
                <InfoOutlinedIcon sx={{ fontSize: 14, color: 'grey.500' }} />
                <Typography
                  sx={{
                    fontSize: { xs: 12, md: 13 },
                    fontWeight: 500,
                    color: 'grey.500',
                  }}>
                  {validityText}
                </Typography>
              </Box>
            )}
          </Box>
        ) : (
          // ── Non-adjustable: show fixed credit amount in a styled card ──
          <Box
            sx={{
              display: 'flex',
              flexDirection: 'column',
              mt: { xs: 2, md: 3 },
              borderRadius: '20px',
              backdropFilter: 'blur(12px)',
              bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.08)' : 'rgba(59,130,246,0.04)'),
              border: '1px solid',
              borderColor: (theme) =>
                theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.18)' : 'rgba(59,130,246,0.10)',
              boxShadow: (theme) =>
                theme.palette.mode === 'dark' ? '0 8px 32px rgba(59,130,246,0.06)' : '0 8px 32px rgba(59,130,246,0.04)',
            }}>
            <Box sx={{ p: { xs: 2.5, md: 3.5 } }}>
              <Typography
                sx={{
                  fontSize: { xs: 13, md: 14 },
                  fontWeight: 600,
                  color: 'text.secondary',
                  mb: 1,
                }}>
                {t('payment.checkout.creditTopup.willReceive')}
              </Typography>
              <Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
                <Typography
                  sx={{
                    fontSize: { xs: 32, md: 48 },
                    fontWeight: 800,
                    lineHeight: 1,
                    letterSpacing: '-0.03em',
                    color: 'primary.main',
                  }}>
                  {formatCreditForCheckout(actualCreditsFormatted, currencySymbol, locale)}
                </Typography>
              </Box>
            </Box>
            {/* Validity footer */}
            {validityText && (
              <Box
                sx={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: 0.75,
                  px: { xs: 2.5, md: 3.5 },
                  py: { xs: 1.5, md: 2 },
                  borderTop: '1px solid',
                  borderColor: (theme) =>
                    theme.palette.mode === 'dark' ? 'rgba(59,130,246,0.15)' : 'rgba(59,130,246,0.08)',
                }}>
                <AccessTimeOutlinedIcon sx={{ fontSize: 14, color: 'grey.500' }} />
                <Typography
                  sx={{
                    fontSize: { xs: 12, md: 13 },
                    fontWeight: 500,
                    color: 'grey.500',
                  }}>
                  {validityText}
                </Typography>
              </Box>
            )}
          </Box>
        )}
      </Box>
      {/* End main content */}

      {/* Exchange rate — shown for all dynamic pricing scenarios */}
      <Box sx={{ flexShrink: 0 }}>
        {rate.hasDynamicPricing && rate.status === 'unavailable' && !isStripe && (
          <Stack direction="row" alignItems="center" spacing={0.75} sx={{ mb: 2 }}>
            <Typography sx={{ fontSize: 13, color: 'text.secondary', fontWeight: 500 }}>
              {t('payment.dynamicPricing.unavailable.title')}
            </Typography>
            <Typography
              component="span"
              onClick={rate.refresh}
              sx={{
                fontSize: 13,
                color: 'primary.main',
                fontWeight: 600,
                cursor: 'pointer',
                '&:hover': { textDecoration: 'underline' },
              }}>
              {t('payment.dynamicPricing.unavailable.retry')}
            </Typography>
          </Stack>
        )}
        <ExchangeRateFooter
          hasDynamicPricing={rate.hasDynamicPricing}
          rate={{
            value: rate.value,
            display: rate.display,
            provider: rate.provider,
            providerDisplay: rate.providerDisplay,
            fetchedAt: rate.fetchedAt,
            status: rate.status,
          }}
          slippage={{ percent: slippage.percent, set: slippage.set }}
          currencySymbol={currency?.symbol || ''}
          isSubscription={['subscription', 'setup'].includes(session?.mode || 'payment')}
        />
      </Box>
    </Box>
  );
}
