/* eslint-disable @typescript-eslint/no-explicit-any */
import './style.css'

import { CircularProgress, ThemeOptions } from '@mui/material'
import Backdrop from '@mui/material/Backdrop'
import Button from '@mui/material/Button'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import { CSSProperties } from '@mui/styles'
import { Stripe, StripeElementsOptions } from '@stripe/stripe-js'
import axios, { AxiosError } from 'axios'
import { Field, Form, Formik, FormikHelpers, FormikProps, FormikValues } from 'formik'
import _find from 'lodash/find'
import _forEach from 'lodash/forEach'
import _get from 'lodash/get'
import _identity from 'lodash/identity'
import _isEmpty from 'lodash/isEmpty'
import _isEqual from 'lodash/isEqual'
import _map from 'lodash/map'
import { nanoid } from 'nanoid'
import React, { FC, useCallback, useEffect, useRef, useState } from 'react'

import {
  AttributesConfig,
  checkEmailExists,
  getCart,
  getCheckoutPageConfigs,
  getCountries,
  getPaymentData,
  getProfileData,
  getStates,
  postOnCheckout,
  setCustomHeader,
} from '../../api'
import { updateCheckout } from '../../api/checkout'
import { withCustomFields } from '../../hoc'
import { usePixel } from '../../hooks/usePixel'
import { IBillingInfoData } from '../../types'
import { ICheckoutResponseData } from '../../types/api/checkout'
import {
  createCheckoutDataBodyWithDefaultHolder,
  deleteCookieByName,
  getCookieByName,
  isBrowser,
  setLoggedUserData,
} from '../../utils'
import { ErrorFocus } from '../../utils/formikErrorFocus'
import { emailRegex } from '../../validators'
import { AddonsContainter, IAddonContainterProps } from '../addonsContainer'
import SimpleAddonsContainer from '../addonsContainer/SimpleAddonsContainer'
import SnackbarAlert from '../common/SnackbarAlert'
import { ForgotPasswordModal } from '../forgotPasswordModal'
import { VerificationPendingModal } from '../idVerificationContainer/VerificationPendingModal'
import { LoginModal } from '../loginModal'
import { IPaymentPage, PaymentContainer } from '../paymentContainer'
import { SignupModal } from '../signupModal'
import TimerWidget from '../timerWidget'
import { usePaymentRedirect, useStripePayment } from './hooks'
import {
  assingUniqueIds,
  createCheckoutDataBody,
  filterBillingInfoFields,
  getFieldComponent,
  getFieldLabel,
  getInitialValues,
  getValidateFunctions,
  ICheckoutBody,
  renderComponentWithProps,
} from './utils'

export interface IBillingInfoPage {
  data?: IBillingInfoData[];
  ticketHoldersFields?: IBillingInfoData;
  handleSubmit?: (
    values: FormikValues,
    formikHelpers: FormikHelpers<FormikValues>,
    eventId: any,
    res: any,
    checkoutUpdateResponse?: any,
    paymentResponse?: any
  ) => void;
  onRegisterSuccess?: (value: any) => void;
  onRegisterError?: (e: AxiosError, email: string) => void;
  onSubmitError?: (e: AxiosError) => void;
  onGetCartSuccess?: (res: any) => void;
  onGetCartError?: (e: AxiosError) => void;
  onGetCountriesSuccess?: (res: any) => void;
  onGetCountriesError?: (e: AxiosError) => void;
  onGetStatesSuccess?: (res: any) => void;
  onGetStatesError?: (e: AxiosError) => void;
  onGetProfileDataSuccess?: (res: any) => void;
  onGetProfileDataError?: (e: AxiosError) => void;
  onGetCheckoutConfigsSuccess?: (res: any) => void;
  onGetCheckoutConfigsError?: (e: AxiosError) => void;
  onLogin?: () => void;
  onLoginSuccess?: () => void;
  onErrorClose?: () => void;
  onCheckoutUpdateSuccess?: (res: any) => void;
  onCheckoutUpdateError?: (e: AxiosError) => void;
  initialValues?: FormikValues;
  buttonName?: string;
  freeOrderButtonName?: string;
  theme?: 'light' | 'dark';
  isLoggedIn?: boolean;
  accountInfoTitle?: string | JSX.Element;
  hideLogo?: boolean;
  themeOptions?: ThemeOptions & {
    input?: CSSProperties;
    checkbox?: CSSProperties;
  };
  hideErrorsAlertSection?: boolean;
  onSkipBillingPage: (data: any) => void;
  skipPage?: boolean;
  canSkipHolderNames?: boolean;
  shouldFetchCountries?: boolean;
  onForgotPasswordSuccess?: (res: any) => void;
  onForgotPasswordError?: (e: AxiosError) => void;
  onCountdownFinish?: () => void;
  enableTimer?: boolean;
  logo?: string;
  showForgotPasswordButton?: boolean;
  showSignUpButton?: boolean;
  brandOptIn?: boolean;
  showPoweredByImage?: boolean;
  isCountryCodeEditable?: boolean;
  customFieldsOrderKeys?: string[];
  customFieldsTicketHolderKeys?: string[];
  onPendingVerification?: () => void;
  includeAddons?: boolean;
  addonsProps?: IAddonContainterProps;
  addOnDataWithCustomFields?: any;
  isSinglePageCheckout?: boolean;
  paymentProps?: Partial<IPaymentPage>;
  paymentSectionAddon?: React.ReactNode;
}

const LogicRunner: FC<{
  brandOptIn?: boolean;
  values: any;
  errors: any;
  setStates: React.Dispatch<any>;
  setFieldValue: any;
  setValues: any;
  setUserValues: any;
  onGetStatesSuccess: any;
  onGetStatesError: any;
  shouldFetchCountries: boolean;
}> = ({
  values,
  setStates,
  setFieldValue,
  setValues,
  setUserValues,
  onGetStatesSuccess,
  onGetStatesError,
  shouldFetchCountries,
  brandOptIn,
}) => {
  const prevCountry = useRef(values.country)
  const prevBuyerData = useRef({
    firstName: '',
    lastName: '',
    email: '',
    phone: '',
  })
  const hasLoadedUserData = useRef(false)
  useEffect(() => {
    const fetchStates = async () => {
      try {
        const res = await getStates(values.country)
        const mappedStates = _map(res.data, (item, key) => ({
          label: item,
          value: key,
        }))
        setStates(mappedStates)
        if (prevCountry.current !== values.country) {
          const stateExists = mappedStates.find(
            state => state.value === values.state
          )?.value
          setFieldValue('state', stateExists ?? mappedStates[0]?.value ?? '')
          prevCountry.current = values.country
        }
        onGetStatesSuccess(res.data)
      } catch (e) {
        if (axios.isAxiosError(e)) {
          onGetStatesError(e)
        }
      }
    }
    shouldFetchCountries && fetchStates()
  }, [values.country, setStates, setFieldValue])

  // Auto-fill first holder with buyer data
  useEffect(() => {
    const buyerFirstName = values.firstName || ''
    const buyerLastName = values.lastName || ''
    const buyerEmail = values.email || ''
    const buyerPhone = values.phone || ''

    // Check if any buyer data has changed
    const firstNameChanged = prevBuyerData.current.firstName !== buyerFirstName
    const lastNameChanged = prevBuyerData.current.lastName !== buyerLastName
    const emailChanged = prevBuyerData.current.email !== buyerEmail
    const phoneChanged = prevBuyerData.current.phone !== buyerPhone

    // Update holder fields individually based on what changed
    if (firstNameChanged) {
      setFieldValue('holderFirstName-0', buyerFirstName, false)
      prevBuyerData.current.firstName = buyerFirstName
    }

    if (lastNameChanged) {
      setFieldValue('holderLastName-0', buyerLastName, false)
      prevBuyerData.current.lastName = buyerLastName
    }

    if (emailChanged) {
      setFieldValue('holderEmail-0', buyerEmail, false)
      prevBuyerData.current.email = buyerEmail
    }

    if (phoneChanged) {
      setFieldValue('holderPhone-0', buyerPhone, false)
      prevBuyerData.current.phone = buyerPhone
    }
  }, [values.firstName, values.lastName, values.email, values.phone, setFieldValue])

  const userDataEncoded = isBrowser ? window.localStorage.getItem('user_data') : ''
  useEffect(() => {
    // set user data from local storage only on initial load
    const getStoredUserData = () => {
      if (isBrowser && userDataEncoded && !hasLoadedUserData.current) {
        try {
          const parsedData = JSON.parse(userDataEncoded)
          const mappedValues = {
            firstName: parsedData?.first_name || parsedData?.firstName || '',
            lastName: parsedData?.last_name || parsedData?.lastName || '',
            email: parsedData?.email || '',
            phone: parsedData?.phone || '',
            confirmEmail: parsedData?.email || '',
            state: parsedData?.state || '',
            street_address: parsedData?.street_address || '',
            country: parsedData?.country || '1',
            zip: parsedData?.zip || '',
            brand_opt_in: brandOptIn ? brandOptIn : parsedData?.brand_opt_in || false,
            city: parsedData?.city || '',
            confirmPassword: '',
            password: '',
            'holderFirstName-0': parsedData?.first_name || parsedData?.firstName || '',
            'holderLastName-0': parsedData?.last_name || parsedData?.lastName || '',
            'holderEmail-0': parsedData?.email || '',
            'holderPhone-0': parsedData?.phone || '',
          }

          const extraDataJSON = window.localStorage.getItem('extraData')
          const extraData = extraDataJSON ? JSON.parse(extraDataJSON) : null

          setValues({ ...values, ...mappedValues, ...(extraData ?? {}) })
          setUserValues(mappedValues)
          hasLoadedUserData.current = true
        } catch (e) {}
      }
    }
    getStoredUserData()
    // Only run on mount or when userDataEncoded first becomes available
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])
  return null
}

// Component to check if email exists
/**
 * A utility component that checks if an email address already exists in the system.
 *
 * Performs debounced validation and existence checking for user email addresses.
 * Only checks when both email and confirmEmail match, are valid, and user is not logged in.
 *
 * @param email - The primary email address to check
 * @param confirmEmail - The confirmation email address (must match email)
 * @param isLoggedIn - Whether the user is currently logged in
 * @param setEmailExists - Callback function to update the email existence state
 *
 * @remarks
 * - Uses a 500ms debounce to avoid excessive API calls
 * - Validates email format using regex before checking existence
 * - Automatically returns false if user is logged in
 * - Returns null as it's a logic-only component with no UI
 */
const EmailExistenceChecker: FC<{
  email: string;
  confirmEmail: string;
  isLoggedIn: boolean;
  setEmailExists: (exists: boolean) => void;
}> = ({ email, confirmEmail, isLoggedIn, setEmailExists }) => {
  useEffect(() => {
    const checkEmail = async () => {
      // Don't check if user is logged in
      if (isLoggedIn) {
        setEmailExists(false)
        return
      }

      // Only check if both emails exist, match, and are valid
      if (!email || !confirmEmail || email !== confirmEmail || !emailRegex.test(email)) {
        setEmailExists(false)
        return
      }

      // Check if email exists
      try {
        const result = await checkEmailExists(email)
        setEmailExists(result.exists)
      } catch {
        setEmailExists(false)
      }
    }

    // Debounce the check
    const timeoutId = setTimeout(() => {
      checkEmail()
    }, 800)

    return () => clearTimeout(timeoutId)
  }, [email, confirmEmail, isLoggedIn, setEmailExists])

  return null
}

const BillingInfoContainer = React.memo(
  ({
    data = [],
    ticketHoldersFields = {
      id: 1,
      fields: [],
    },
    initialValues = {},
    buttonName = 'Submit',
    freeOrderButtonName = 'Complete Registration',
    handleSubmit = _identity,
    theme = 'light',
    onRegisterSuccess = _identity,
    onRegisterError = _identity,
    onSubmitError = _identity,
    onGetCartSuccess = _identity,
    onGetCartError = _identity,
    onGetCountriesSuccess = _identity,
    onGetCountriesError = _identity,
    onGetStatesSuccess = _identity,
    onGetStatesError = _identity,
    onGetProfileDataSuccess = _identity,
    onGetProfileDataError = _identity,
    onLogin,
    onLoginSuccess = _identity,
    onCheckoutUpdateSuccess = _identity,
    onCheckoutUpdateError = _identity,
    isLoggedIn: pIsLoggedIn = false,
    accountInfoTitle = '',
    hideLogo,
    themeOptions,
    onErrorClose = _identity,
    hideErrorsAlertSection = false,
    onSkipBillingPage = _identity,
    skipPage = false,
    canSkipHolderNames = false,
    onForgotPasswordSuccess = _identity,
    onForgotPasswordError = _identity,
    shouldFetchCountries = true,
    onCountdownFinish = _identity,
    enableTimer = false,
    logo,
    showForgotPasswordButton = true,
    showSignUpButton = false,
    brandOptIn = false,
    showPoweredByImage = false,
    customFieldsOrderKeys,
    customFieldsTicketHolderKeys,
    isCountryCodeEditable = true,
    onPendingVerification = _identity,
    onGetCheckoutConfigsSuccess = _identity,
    onGetCheckoutConfigsError = _identity,
    includeAddons = false,
    addonsProps,
    addOnDataWithCustomFields,
    isSinglePageCheckout = false,
    paymentProps = {},
    paymentSectionAddon,
  }: IBillingInfoPage) => {
    const [extraData, setExtraData] = useState(null)
    const [isConfigLoading, setIsConfigLoading] = useState(true)
    const [configs, setConfigs] = useState<null | AttributesConfig>(null)
    const isNewUser = false
    const themeMui = createTheme(themeOptions)
    const elementsRef = useRef<any>(null)
    const stripeRef = useRef<Stripe | null>(null)

    useEffect(() => {
      if (isBrowser) {
        const extraData = window.localStorage.getItem('extraData')
        if (extraData) {
          setExtraData(JSON.parse(extraData))
        }
      }
      getCheckoutPageConfigs()
        .then(data => {
          if (data?.data?.attributes) {
            setConfigs(data.data.attributes)
            setIsConfigLoading(false)
          }
          onGetCheckoutConfigsSuccess(data)
        })
        .catch(e => {
          setIsConfigLoading(false)
          onGetCheckoutConfigsError(e)
        })
    }, [isBrowser])

    const defaultCountry = isBrowser ? window.localStorage.getItem('eventCountry') : ''
    const userData =
      isBrowser && window.localStorage.getItem('user_data')
        ? JSON.parse(window.localStorage.getItem('user_data') || '{}')
        : {}
    const additionalConfigs =
      isBrowser && window.localStorage.getItem('checkoutAdditionalConfigs')
        ? JSON.parse(
            window.localStorage.getItem('checkoutAdditionalConfigs') ||
              '{"resale": false, "resaleWithAddons": false}'
          )
        : { resale: false, resaleWithAddons: false }
    const [dataWithUniqueIds, setDataWithUniqueIds] = useState<IBillingInfoData[]>(
      assingUniqueIds(data)
    )
    const xtfCookie = getCookieByName('X-TF-ECOMMERCE')
    const [isLoggedIn, setIsLoggedIn] = useState(!!(pIsLoggedIn || xtfCookie))
    const [cartInfoData, setCartInfo] = useState<any>({})
    const [countries, setCountries] = useState<any>([])
    const [states, setStates] = useState<any>([])
    const [showModalLogin, setShowModalLogin] = useState(false)
    const alreadyHasUser= false
    const [userExpired, setUserExpired] = useState(false)
    const [showModalSignup, setShowModalSignup] = useState(false)
    const [showModalForgotPassword, setShowModalForgotPassword] = useState(false)
    const [ticketsQuantity, setTicketsQuantity] = useState<string[]>([])
    const [userValues, setUserValues] = useState<any>({
      firstName: '',
      lastName: '',
      email: '',
      phone: '',
      confirmEmail: '',
      holderFirstName: '',
      holderLastName: '',
      holderAge: '',
      city: '',
      country: '',
      street_address: '',
      state: '',
      zip: '',
    })
    const [loading, setLoading] = useState(true)
    const [cardLoading, setCardLoading] = useState(false)
    const [isCountriesLoading, setIsCountriesLoading] = useState(true)
    const [error, setError] = useState<string | null>(null)
    const [phoneValidationIsLoading, setPhoneValidationIsLoading] = useState(false)
    const [emailExists, setEmailExists] = useState(false)
    const emailLogged = _get(userData, 'email', '') || _get(userValues, 'email', '')
    const firstNameLogged =
      _get(userData, 'first_name', '') || _get(userValues, 'first_name', '')
    const lastNameLogged =
      _get(userData, 'last_name', '') || _get(userValues, 'last_name', '')
    const phoneLogged = _get(userData, 'phone', '') || _get(userValues, 'phone', '')
    const showDOB = configs?.age_required
    const showTicketHolders = configs?.names_required
    const eventId = configs?.event_id
    const optedInFieldValue: boolean = brandOptIn
      ? brandOptIn
      : _get(cartInfoData, 'optedIn', false)
    const ttfOptIn = Boolean(_get(cartInfoData, 'ttfOptIn', false))
    const isTable = Boolean(_get(cartInfoData, 'is_table', false))
    const hideTtfOptIn: boolean = _get(cartInfoData, 'hide_ttf_opt_in', true)
    const expirationTime = _get(cartInfoData, 'expiresAt')
    const flagRequirePhone = configs?.phone_required
    const collectMandatoryWalletAddress = configs?.collect_mandatory_wallet_address
    const collectOptionalWalletAddress = configs?.collect_optional_wallet_address
    const flagFreeTicket = configs?.free_ticket
    const hidePhoneField = configs?.hide_phone_field
    const hideWalletAddressField =
      !collectOptionalWalletAddress && !collectMandatoryWalletAddress
    const collectMandatoryCompany = configs?.collect_mandatory_company
    const collectOptionalCompany = configs?.collect_optional_company
    const hideCompanyField = !collectOptionalCompany && !collectMandatoryCompany
    const collectMandatoryJobTitle = configs?.collect_mandatory_job_title
    const collectOptionalJobTitle = configs?.collect_optional_job_title
    const hideJobTitleField = !collectMandatoryJobTitle && !collectOptionalJobTitle
    const collectMandatoryInstagram = configs?.collect_mandatory_instagram
    const collectOptionalInstagram = configs?.collect_optional_instagram
    const hideInstagramField = !collectMandatoryInstagram && !collectOptionalInstagram
    const collectMandatoryBusinessCategory = configs?.collect_mandatory_business_category
    const collectOptionalBusinessCategory = configs?.collect_optional_business_category
    const eventHasAddons = configs?.has_add_on
    const addonMaxQuantityGroups = configs?.addon_max_quantity_groups ?? undefined
    const hideBusinessCategoryField =
      !collectMandatoryBusinessCategory && !collectOptionalBusinessCategory

    const [pendingVerificationMessage, setPendingVerificationMessage] = useState<string>()
    const [reviewData, setReviewData] = useState<any>({})
    const [checkoutData, setCheckoutData] = useState<any>({})
    const [checkoutUpdateData, setCheckoutUpdateData] =
      useState<ICheckoutResponseData | null>(null)
    const prevData = useRef(data)

    const addAddOnsInAttributes = useCallback((checkoutBody: any) => {
      const selectedAddOns = window.localStorage.getItem('add_ons') || '{}'
      const addOnDataCapture = window.localStorage.getItem('add_on_data_capture') || '{}'

      checkoutBody.attributes.add_ons = JSON.parse(selectedAddOns)
      checkoutBody.attributes.add_on_data_capture = JSON.parse(addOnDataCapture)
    }, [])
    const [singleCheckoutAddons, setSingleCheckoutAddOns] = useState<any>({})

    const orderIsFree = !Number(checkoutData?.total)

    useEffect(() => {
      const hasUniqueId = _get(data, '[0].uniqueId')
      const isEqualData = _isEqual(prevData.current, data)
      if (!hasUniqueId || !isEqualData) {
        setDataWithUniqueIds(assingUniqueIds(data))
        if (!isEqualData) {
          prevData.current = data
        }
      }
    }, [data])

    const getQuantity = useCallback((cart: any = []) => {
      let qty = 0
      cart.forEach((item: any) => {
        qty += +item.quantity
      })
      return qty
    }, [])

    useEffect(() => {
      if (pIsLoggedIn !== isLoggedIn || xtfCookie) {
        setIsLoggedIn(!!(pIsLoggedIn || xtfCookie))
      }
    }, [pIsLoggedIn, isLoggedIn, xtfCookie])

    //just once
    useEffect(() => {
      // fetch countries data
      const fetchCountries = async () => {
        try {
          const res = await getCountries()
          setCustomHeader(res)
          setCountries(res.data)
          setIsCountriesLoading(false)
          onGetCountriesSuccess(res.data)
        } catch (e) {
          if (axios.isAxiosError(e)) {
            onGetCountriesError(e)
          }
          setIsCountriesLoading(false)
        }
      }
      shouldFetchCountries && fetchCountries()
      fetchCart()

      // Initialize checkout with event_id on first load
      if (isSinglePageCheckout && eventId) {
        updateCheckoutWithAddOns()
      }

      return () => {
        isBrowser && localStorage.removeItem('selectedTicketsQuantity')
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [
      eventId,
      isSinglePageCheckout,
      shouldFetchCountries,
      onGetCountriesSuccess,
      onGetCountriesError,
    ])

    // fetch cart data
    const fetchCart = async () => {
      try {
        setCardLoading(true)
        const res = await getCart()
        setCustomHeader(res)
        const cartInfo = res.data.attributes
        setCartInfo(cartInfo)
        const { cart = [] } = cartInfo
        setTicketsQuantity(new Array(getQuantity(cart)).fill(null).map(() => nanoid()))
        onGetCartSuccess(res.data)
      } catch (e) {
        if (axios.isAxiosError(e)) {
          onGetCartError(e)
        }
      } finally {
        setCardLoading(false)
      }
    }

    // fetch user data
    const fetchUserData = async () => {
      try {
        if (isLoggedIn) {
          const userDataResponse = await getProfileData()
          const profileSpecifiedData = _get(userDataResponse, 'data')
          const profileDataObj = setLoggedUserData(profileSpecifiedData)
          setUserValues({
            ...profileDataObj,
            firstName: profileDataObj.first_name,
            lastName: profileDataObj.last_name,
          })
          window.localStorage.setItem('user_data', JSON.stringify(profileDataObj))
          onGetProfileDataSuccess(userDataResponse.data)
        }
      } catch (e) {
        if (axios.isAxiosError(e)) {
          onGetProfileDataError(e)
        }
      }
    }

    useEffect(() => {
      fetchUserData()
      fetchCart()
    }, [isLoggedIn])

    useEffect(() => {
      const fetchCheckoutUpdate = async () => {
        if (!eventId) return

        try {
          const checkoutUpdateResponse = await updateCheckout({
            attributes: {
              event_id: eventId,
              is_from_resale: additionalConfigs?.resale,
            },
          })
          if (checkoutUpdateResponse.success) {
            const checkoutAttributes = checkoutUpdateResponse.data.attributes
            const cartPriceBreakdown = _get(
              checkoutAttributes,
              'cart_price_breakdown',
              {}
            )
            localStorage.setItem(
              'checkoutData',
              JSON.stringify({ hash: '', total: _get(cartPriceBreakdown, 'total', 0) })
            )
            setCheckoutUpdateData(checkoutAttributes)
            onCheckoutUpdateSuccess({ expires_at: expirationTime, ...cartPriceBreakdown })
          }
        } catch (error) {
          console.error('Failed to fetch checkout update:', error)
        }
      }

      fetchCheckoutUpdate()
    }, [eventId, additionalConfigs?.resale])

    useEffect(() => {
      const collectPaymentData = async () => {
        if (
          skipPage &&
          !_isEmpty(ticketsQuantity) &&
          !showDOB &&
          !loading &&
          !isNewUser
        ) {
          setLoading(true)
          const checkoutBody = createCheckoutDataBodyWithDefaultHolder(
            ticketsQuantity.length,
            userData
          )

          try {
            if (isBrowser) {
              addAddOnsInAttributes(checkoutBody)
            }

            const checkoutResponse = await postOnCheckout(checkoutBody, flagFreeTicket)
            removeReferralKey()
            removeAdditionalConfigs()
            onSkipBillingPage(checkoutResponse.data.attributes)
            setLoading(false)
          } catch (e) {
            onSubmitError(e as AxiosError)
            if (_get(e, 'response.data.data.hasUnverifiedOrder')) {
              setPendingVerificationMessage(_get(e, 'response.data.message'))
            }
          }
        } else {
          setLoading(false)
        }
      }
      collectPaymentData()
    }, [skipPage, ticketsQuantity])

    const collectCheckoutBody = useCallback(
      (values: Record<string, any>, profileData?: any): Record<string, any> => {
        let checkoutBody = {} as ICheckoutBody

        // Auto collect ticket holders name when it was skipped optionally
        if (showDOB && !showTicketHolders && canSkipHolderNames) {
          checkoutBody = createCheckoutDataBodyWithDefaultHolder(
            ticketsQuantity.length,
            values,
            true,
            { emailLogged, firstNameLogged, lastNameLogged, phoneLogged }
          )
        } else {
          checkoutBody = createCheckoutDataBody(
            ticketsQuantity.length,
            values,
            {
              emailLogged: emailLogged || profileData.email,
              firstNameLogged:
                firstNameLogged || profileData.first_name || profileData.firstName,
              lastNameLogged:
                lastNameLogged || profileData.last_name || profileData.lastName,
              phoneLogged: phoneLogged || profileData.phone,
            },
            showDOB
          )
        }

        // Collect data_capture for Order Custom Fields
        const data_capture: Record<string, any> = {}
        _forEach(customFieldsOrderKeys, (key: string) => {
          data_capture[key] = values[key]

          // Delete from values list
          delete checkoutBody.attributes[key]
        })

        // Temp solution for hardcoded data capture values, to be deleted in the future
        const captureKeys = [
          'businessCategory',
          'company',
          'instagram',
          'jobTitle',
          'wallet_address',
        ]

        captureKeys.forEach(key => {
          const path = `data_capture.${key}`
          const value = _get(values, path, '')

          if (value !== '') {
            data_capture[key] = value
          }

          const attributeKey = `data_capture[${key}]`
          delete checkoutBody.attributes?.[attributeKey]
        })

        // Collect data_capture for Ticket Holders Fields
        _forEach(checkoutBody.attributes.ticket_holders, (holder, holderIndex) => {
          const holderDataCapture: Record<string, any> = {}

          _forEach(customFieldsTicketHolderKeys, customFieldKey => {
            const customFieldHolderName = `${customFieldKey}-${holderIndex}`
            const customFieldHolderKey = values[customFieldHolderName] || ''
            holderDataCapture[customFieldKey] = customFieldHolderKey

            // Delete holder specific value from values list
            delete checkoutBody.attributes[customFieldHolderName]
          })

          // Assign Ticket Holder data_capture final value
          if (!_isEmpty(holderDataCapture)) {
            holder.ticket_data_capture = holderDataCapture
          }
        })

        // Collect add_on_data_capture for Add-on Custom Fields
        const add_on_data_capture: Record<string, any> = {}
        _forEach(values, (val: any, key: string) => {
          // Matches keys like: `${addonId}-${groupId}-${fieldKey}` created in AddonComponent
          const match = key.match(/^(\d+)-\d+-(.+)$/)
          if (match) {
            const addonId = match[1]
            const fieldKey = match[2]

            // Initialize addon bucket
            if (!add_on_data_capture[addonId]) {
              add_on_data_capture[addonId] = {}
            }

            add_on_data_capture[addonId][fieldKey] = val

            // Remove the raw form key from attributes to avoid leaking internals
            delete checkoutBody.attributes[key]
          }
        })

        // Also include add_on_data_capture from localStorage for single-page checkout
        if (isBrowser) {
          const storedAddOnDataCapture = localStorage.getItem('add_on_data_capture')
          if (storedAddOnDataCapture) {
            const parsed = JSON.parse(storedAddOnDataCapture)
            Object.keys(parsed).forEach(addonId => {
              if (!add_on_data_capture[addonId]) {
                add_on_data_capture[addonId] = {}
              }
              Object.keys(parsed[addonId]).forEach(fieldKey => {
                add_on_data_capture[addonId][fieldKey] = parsed[addonId][fieldKey]
              })
            })
          }
        }

        const mergedAttributes: Record<string, any> = {
          ...checkoutBody.attributes,
          data_capture,
        }

        if (!_isEmpty(add_on_data_capture)) {
          mergedAttributes.add_on_data_capture = add_on_data_capture
        }

        return { attributes: mergedAttributes }
      },
      [
        showDOB,
        showTicketHolders,
        canSkipHolderNames,
        customFieldsOrderKeys,
        ticketsQuantity.length,
        emailLogged,
        firstNameLogged,
        lastNameLogged,
        phoneLogged,
        customFieldsTicketHolderKeys,
      ]
    )

    const removeReferralKey = useCallback(() => {
      localStorage.removeItem('referral_key')
    }, [])

    const removeAdditionalConfigs = useCallback(() => {
      localStorage.removeItem('checkoutAdditionalConfigs')
    }, [])

    useEffect(() => {
      onCheckoutUpdateSuccess({ expires_at: expirationTime, ...checkoutData })
    }, [checkoutData, cartInfoData])

    // Initialize payment hooks
    usePaymentRedirect({
      stripeRef,
      setError,
      setLoading,
      removeReferralKey,
      removeAdditionalConfigs,
      handleSubmit,
      isBrowser,
    })

    const { processPayment } = useStripePayment({
      stripeRef,
      elementsRef,
      setError,
      isBrowser,
    })

    const updateCheckoutWithAddOns = useCallback(
      async (addOns: { [key: string]: number } = {}) => {
        if (!isSinglePageCheckout) return

        const mergedAddOns = { ...singleCheckoutAddons }

        // Update existing entries and add new ones
        Object.entries(addOns).forEach(([key, value]) => {
          const amount = Number(value)
          if (amount) {
            mergedAddOns[key] = amount
          } else {
            delete mergedAddOns[key]
          }
        })

        try {
          const checkoutUpdateData = {
            attributes: {
              event_id: eventId,
              add_ons: mergedAddOns,
              is_from_resale: additionalConfigs?.resale,
            },
          }

          const checkoutResponse = await updateCheckout(checkoutUpdateData)

          if (checkoutResponse.success) {
            const checkoutDataObj = _get(
              checkoutResponse,
              'data.attributes.cart_price_breakdown',
              {}
            )
            setCheckoutData(checkoutDataObj)
            setSingleCheckoutAddOns(mergedAddOns)
            const updatedAttributes = _get(checkoutResponse, 'data.attributes', {})
            if (updatedAttributes.additional_payment_information) {
              setCheckoutUpdateData(updatedAttributes)
            }
          }
        } catch (error) {
          const errorMessage = _get(
            error,
            'response.data.message',
            'Failed to update add-ons'
          )
          setError(errorMessage)
          onCheckoutUpdateError(error as AxiosError)
        }
      },
      [eventId, isSinglePageCheckout, onCheckoutUpdateError, onCheckoutUpdateSuccess]
    )

    const handleAddOnSelect = useCallback(
      async (selectedAddOns: { [key: string]: number }) => {
        await updateCheckoutWithAddOns(selectedAddOns)
      },
      [updateCheckoutWithAddOns]
    )

    const onAddOnSelect = useCallback(
      (id: string, value: string, _addon: any, fieldUpdates: Record<string, any> = {}) => {
        const quantity = parseInt(value) || 0
        const addonId = id

        // Get current add-ons and their custom fields
        const currentAddOns = JSON.parse(localStorage.getItem('add_ons') || '{}')
        const currentDataCapture = JSON.parse(
          localStorage.getItem('add_on_data_capture') || '{}'
        )

        // Update quantities
        const updatedAddOns = { ...currentAddOns }
        updatedAddOns[addonId] = quantity

        // Update custom fields if any
        const updatedDataCapture = { ...currentDataCapture }
        if (Object.keys(fieldUpdates).length > 0) {
          updatedDataCapture[addonId] = {
            ...(updatedDataCapture[addonId] || {}),
            ...fieldUpdates,
          }
        }

        if (quantity === 0 && updatedDataCapture[addonId]) {
          delete updatedDataCapture[addonId]
        }
        // Save to localStorage
        localStorage.setItem('add_ons', JSON.stringify(updatedAddOns))
        localStorage.setItem('add_on_data_capture', JSON.stringify(updatedDataCapture))

        // Call handleAddOnSelect with the updated addons object
        handleAddOnSelect(updatedAddOns)
      },
      [handleAddOnSelect]
    )
    if (loading || (enableTimer && !expirationTime && isBrowser)) {
      if (expirationTime === 0) {
        // Redirect to homepage (countdown finished and browser reloaded case)
        window.location.href = '/'
      }
    }

    const selectedCountry =
      _find(countries, item => item.code.toLowerCase() === defaultCountry) || {}
    const initialCountry = selectedCountry.id || _get(userData, 'countryId', '') || '1'

    const pageUrl = isBrowser ? window.location.href.split('?')[0] : ''
    usePixel(eventId || cartInfoData?.eventId, { page: 'billing', pageUrl })
    if (isTable) {
      dataWithUniqueIds[0].label = 'Get Your Tables'
    }

    const stripePublishableKey =
      reviewData?.payment_method?.stripe_publishable_key ||
      checkoutUpdateData?.additional_payment_information?.basic_config?.apiKey
    const stripeAccountId =
      reviewData?.payment_method?.stripe_connected_account ||
      checkoutUpdateData?.additional_payment_information?.basic_config?.accountId
    const addOnsIncludedOnInvitation =
      additionalConfigs.resale && additionalConfigs.resaleWithAddons

    const elementsOptions: StripeElementsOptions = {
      ...checkoutUpdateData?.additional_payment_information?.elements_config,
    }

    if (loading || cardLoading || isCountriesLoading || isConfigLoading || !eventId) {
      return (
        <Backdrop
          sx={{ color: '#fff', backgroundColor: '#000000bd', zIndex: 1205 }}
          open={true}
        >
          <CircularProgress color="inherit" />
        </Backdrop>
      )
    }

    return (
      <ThemeProvider theme={themeMui}>
        {!!expirationTime && enableTimer && (
          <TimerWidget
            expires_at={expirationTime}
            onCountdownFinish={onCountdownFinish}
            container={isSinglePageCheckout ? 'body' : ''}
          />
        )}
        {!isCountriesLoading && !isConfigLoading && (
          <Formik
            initialValues={getInitialValues(
              dataWithUniqueIds,
              {
                country: initialCountry,
                state:
                  _get(userData, 'stateId', '') || _get(userData, 'state', '') || '1',
                brand_opt_in: Boolean(optedInFieldValue),
                ttf_opt_in: ttfOptIn,
                data_capture: {
                  instagram: _get(extraData, 'data_capture.instagram', ''),
                  company: _get(extraData, 'data_capture.company', ''),
                  businessCategory: _get(extraData, 'data_capture.businessCategory', ''),
                  jobTitle: _get(extraData, 'data_capture.jobTitle', ''),
                },
                ...initialValues,
              },
              userValues,
              ticketHoldersFields,
              ticketsQuantity
            )}
            enableReinitialize={false}
            onSubmit={async (values, formikHelpers) => {
              try {
                // Validation: if phone is required for ticket holders, mark errors and stop submit
                const flagRequirePhoneLocal = Boolean(configs?.phone_required)
                if (flagRequirePhoneLocal) {
                  const holdersCount = ticketsQuantity.length
                  let hasHolderPhoneError = false
                  for (let i = 0; i < holdersCount; i++) {
                    const fieldName = `holderPhone-${i}`
                    const value = _get(values, fieldName, '')
                    if (!value) {
                      hasHolderPhoneError = true
                      formikHelpers.setFieldTouched(fieldName, true, false)
                      formikHelpers.setFieldError(fieldName, 'This field is required')
                    }
                  }
                  if (hasHolderPhoneError) {
                    // Do not proceed with submit; Formik will show errors and our PhoneNumberField now shows errors when submitCount > 0
                    return
                  }
                }

                if ((!elementsRef.current || !stripeRef.current) && !orderIsFree) {
                  setError('Fill in the payment details')
                  return
                }

                if (isSinglePageCheckout && !orderIsFree) {
                  // For PaymentElement, we'll use confirmPayment directly
                  // No need to create payment method separately
                }

                if (isBrowser) {
                  window.localStorage.setItem(
                    'extraData',
                    JSON.stringify({
                      data_capture: {
                        instagram: _get(values, 'data_capture.instagram', ''),
                        company: _get(values, 'data_capture.company', ''),
                        businessCategory: _get(
                          values,
                          'data_capture.businessCategory',
                          ''
                        ),
                        jobTitle: _get(values, 'data_capture.jobTitle', ''),
                      },
                    })
                  )
                }

                // Guest checkout: no need to register, just get profile if logged in
                let userDataObj = userData
                if (isLoggedIn) {
                  try {
                    const profileData = await getProfileData()
                    const profileSpecifiedData = _get(profileData, 'data')
                    userDataObj = setLoggedUserData(profileSpecifiedData)
                  } catch (e) {
                    // If profile fetch fails, use values from form
                    userDataObj = {
                      email: values.email,
                      first_name: values.firstName,
                      last_name: values.lastName,
                      phone: values.phone,
                    }
                  }
                } else {
                  // For guest checkout, use form values
                  userDataObj = {
                    email: values.email,
                    first_name: values.firstName,
                    last_name: values.lastName,
                    phone: values.phone,
                  }
                }

                if (isBrowser) {
                  window.localStorage.setItem('user_data', JSON.stringify(userDataObj))
                }

                const checkoutBody = collectCheckoutBody(values, userDataObj)

                if (isBrowser && !isSinglePageCheckout) {
                  addAddOnsInAttributes(checkoutBody)
                }

                if (isSinglePageCheckout) {
                  checkoutBody.attributes.add_ons = singleCheckoutAddons
                  // Include add_on_data_capture for single-page checkout
                  const storedAddOnDataCapture =
                    localStorage.getItem('add_on_data_capture')
                  if (storedAddOnDataCapture) {
                    checkoutBody.attributes.add_on_data_capture =
                      JSON.parse(storedAddOnDataCapture)
                  }
                }

                const checkoutResponse = await postOnCheckout(
                  checkoutBody,
                  flagFreeTicket
                )

                const checkoutUpdateResponse = await updateCheckout({
                  attributes: {
                    event_id: eventId,
                    add_ons: checkoutBody?.attributes?.add_ons ?? [],
                    is_from_resale: additionalConfigs?.resale,
                  },
                })
                setCheckoutUpdateData(checkoutUpdateResponse.data.attributes)

                let paymentResponse = null

                if (isSinglePageCheckout) {
                  const { hash, total } = checkoutResponse.data.attributes
                  localStorage.setItem('checkoutData', JSON.stringify({ hash, total }))

                  const paymentDataResponse = await getPaymentData(String(hash))

                  if (paymentDataResponse.success) {
                    const { attributes } = paymentDataResponse.data
                    setReviewData(attributes)

                    const { order_details, cart } = attributes
                    const {
                      tickets: [ticket],
                    } = order_details

                    const updatedOrderData = {
                      add_ons: order_details.add_ons || [],
                      total: order_details.total,
                      subtotal: order_details.subtotal,
                      fees: order_details.fees,
                      pay_now: order_details.pay_now || '',

                      id: order_details?.id,
                      product_name: cart[0]?.product_name,
                      ticketType: ticket?.name,
                      quantity: ticket?.quantity,
                      price: ticket?.price,
                      currency: order_details?.currency,
                      guest_count: order_details?.guest_count || '',
                      debt: order_details?.debt || null,
                      cost: ticket?.cost,
                    }

                    const isFreeTickets =
                      (!Number(total) && !Number(updatedOrderData.total)) ||
                      !Number(updatedOrderData?.pay_now || 0)
                    // Process payment using the hook
                    paymentResponse = await processPayment(
                      paymentDataResponse,
                      values,
                      formikHelpers,
                      checkoutResponse,
                      checkoutUpdateResponse,
                      {
                        attributes,
                        isFreeTickets,
                        updatedOrderData,
                        eventId,
                      }
                    )

                    if (!paymentResponse && !isFreeTickets) {
                      // Payment failed or redirected, don't continue
                      return
                    }
                  }
                }

                removeReferralKey()
                removeAdditionalConfigs()
                handleSubmit(
                  values,
                  formikHelpers as FormikHelpers<any>,
                  eventId,
                  checkoutResponse,
                  checkoutUpdateResponse,
                  paymentResponse
                )
              } catch (e) {
                setLoading(false)
                onSubmitError(e as AxiosError)
                const hasUnverifiedOrder = _get(
                  e,
                  'response.data.data.hasUnverifiedOrder'
                )
                const message = _get(e, 'response.data.message', {}) as
                  | { password?: string | null, email?: string | null }
                  | string

                if (hasUnverifiedOrder && typeof message === 'string') {
                  setPendingVerificationMessage(message)
                } else if (axios.isAxiosError(e)) {
                  if (
                    (e as any).response?.status === 401 ||
                    _get(e, 'response.data.error') === 'invalid_token'
                  ) {
                    if (isBrowser) {
                      window.localStorage.removeItem('user_data')
                      setUserExpired(true)
                      setShowModalLogin(true)
                      setIsLoggedIn(false)
                      setShowModalSignup(false)
                      setShowModalForgotPassword(false)
                      const event = new window.CustomEvent('tf-logout')
                      deleteCookieByName('X-TF-ECOMMERCE')
                      window.document.dispatchEvent(event)
                    }
                  }
                  if (message && !hideErrorsAlertSection && typeof message === 'string') {
                    setError(message)
                  }
                  onSubmitError(e)
                }

                // Keep form values intact - don't reset
                formikHelpers.setSubmitting(false)
              } finally {
                setLoading(false)
              }
            }}
          >
            {(props: FormikProps<any>) => (
              <Form onSubmit={props.handleSubmit}>
                <ErrorFocus />
                <LogicRunner
                  brandOptIn={brandOptIn}
                  values={props.values}
                  errors={props.errors}
                  setStates={setStates}
                  setFieldValue={props.setFieldValue}
                  setValues={props.setValues}
                  setUserValues={setUserValues}
                  onGetStatesSuccess={onGetStatesSuccess}
                  onGetStatesError={onGetStatesError}
                  shouldFetchCountries={shouldFetchCountries}
                />
                <EmailExistenceChecker
                  email={props.values.email || ''}
                  confirmEmail={props.values.confirmEmail || ''}
                  isLoggedIn={isLoggedIn}
                  setEmailExists={setEmailExists}
                />
                <div className={`billing-info-container ${theme}`}>
                  {!!error && (
                    <SnackbarAlert
                      type="error"
                      isOpen={!!error}
                      message={error || ''}
                      onClose={() => {
                        setError(null)
                        onErrorClose()
                      }}
                    />
                  )}
                  {!isLoggedIn && !isSinglePageCheckout && (
                    <div className="account-actions-block">
                      <div className="action-item">
                        <div>{accountInfoTitle}</div>
                        <div>Login & skip ahead:</div>
                      </div>
                      <div className="action-item login-block">
                        <button
                          className="login-register-button"
                          type="button"
                          onClick={() => {
                            // If outside login needed to skip package login functionallity
                            if (onLogin) {
                              onLogin()
                            } else {
                              setShowModalLogin(true)
                            }
                          }}
                        >
                          Login
                        </button>
                        {!hideLogo && (
                          <div className="logo-image-container">
                            <img
                              src={
                                theme === 'dark'
                                  ? 'https://www.ticketfairy.com/resources/images/logo-ttf.svg'
                                  : 'https://www.ticketfairy.com/resources/images/logo-ttf-black.svg'
                              }
                              alt="nodata"
                            />
                          </div>
                        )}
                      </div>
                    </div>
                  )}
                  {isSinglePageCheckout &&
                  !addOnsIncludedOnInvitation &&
                  eventHasAddons &&
                  eventId ? (
                    <SimpleAddonsContainer
                      {...(addonsProps ?? {})}
                      eventId={eventId}
                      addOnDataWithCustomFields={addOnDataWithCustomFields}
                      configs={configs}
                      onAddOnSelect={onAddOnSelect}
                      addonMaxQuantityGroups={addonMaxQuantityGroups}
                    />
                  ) : !addOnsIncludedOnInvitation &&
                    includeAddons &&
                    !isSinglePageCheckout ? (
                    <AddonsContainter
                      {...(addonsProps ?? {})}
                      addOnDataWithCustomFields={addOnDataWithCustomFields}
                      configs={configs}
                      onAddOnSelect={onAddOnSelect}
                    />
                  ) : null}
                  {!cardLoading &&
                    _map(dataWithUniqueIds, item => {
                      const { label, labelClassName, fields } = item
                      return (
                        <div key={item.uniqueId} className="billing-info-fields">
                          <p className={labelClassName}>{label}</p>
                          {_map(fields, group => {
                            const { groupClassname, groupItems } = group
                            const filteredGroupItems = filterBillingInfoFields(
                              groupItems,
                              {
                                showDOB: Boolean(showDOB),
                                hideTtfOptIn: Boolean(hideTtfOptIn),
                                hidePhoneField: Boolean(hidePhoneField),
                                flagRequirePhone: Boolean(flagRequirePhone),
                                collectMandatoryWalletAddress: Boolean(
                                  collectMandatoryWalletAddress
                                ),
                                collectMandatoryJobTitle: Boolean(
                                  collectMandatoryJobTitle
                                ),
                                collectMandatoryBusinessCategory: Boolean(
                                  collectMandatoryBusinessCategory
                                ),
                                collectMandatoryCompany: Boolean(collectMandatoryCompany),
                                collectMandatoryInstagram: Boolean(
                                  collectMandatoryInstagram
                                ),
                                flagFreeTicket: Boolean(flagFreeTicket),
                                hideWalletAddressField: Boolean(hideWalletAddressField),
                                hideJobTitleField: Boolean(hideJobTitleField),
                                hideBusinessCategoryField: Boolean(
                                  hideBusinessCategoryField
                                ),
                                hideCompanyField: Boolean(hideCompanyField),
                                hideInstagramField,
                              }
                            )
                            return (
                              <React.Fragment key={group.uniqueId}>
                                <div className={groupClassname}>
                                  {_map(filteredGroupItems, element => {
                                    // Hide password fields in single-page checkout or when user is logged in
                                    const shouldHidePasswordFields =
                                      ['password', 'confirmPassword', 'password-info'].includes(
                                        element.name
                                      ) &&
                                      (isLoggedIn || isSinglePageCheckout)

                                    return shouldHidePasswordFields ? null : (
                                      <React.Fragment key={element.uniqueId}>
                                        <div
                                          className={`${element.className} ${
                                            props?.errors[element.name] || ''
                                          }`}
                                        >
                                          {element.component ? (
                                            typeof element.component === 'function' ? (
                                              renderComponentWithProps(
                                                element.component as React.ComponentType<any>,
                                                element.name === 'payment_info'
                                                  ? { reviewData }
                                                  : {}
                                              )
                                            ) : (
                                              element.component
                                            )
                                          ) : (
                                            <Field
                                              {...element}
                                              type={
                                                element.type === 'radio' ||
                                                element.type === 'checkbox'
                                                  ? undefined
                                                  : element.type
                                              }
                                              setPhoneValidationIsLoading={
                                                element.type === 'phone'
                                                  ? setPhoneValidationIsLoading
                                                  : undefined
                                              }
                                              fill={element.type === 'phone' ? true : undefined}
                                              label={getFieldLabel(element, configs)}
                                              validate={getValidateFunctions(
                                                element,
                                                states,
                                                props.values,
                                                props.errors
                                              )}
                                              setFieldValue={props.setFieldValue}
                                              onBlur={props.handleBlur}
                                              component={getFieldComponent(element)}
                                              selectOptions={
                                                element.name === 'country'
                                                  ? _map(countries, item => ({
                                                      value: item.id,
                                                      label: item.name,
                                                    }))
                                                  : element.name === 'state'
                                                  ? [
                                                      {
                                                        label: element.label,
                                                        value: '',
                                                        disabled: true,
                                                      },
                                                      ...states,
                                                    ]
                                                  : element.selectOptions || []
                                              }
                                              theme={theme}
                                              defaultCountry={
                                                defaultCountry || element.defaultCountry
                                              }
                                              dateFormat={element.format}
                                              isCountryCodeEditable={
                                                isCountryCodeEditable
                                              }
                                            />
                                          )}
                                        </div>
                                      </React.Fragment>
                                    )
                                  })}
                                </div>
                                {/* Show login suggestion if email is registered */}
                                {group.groupItems.some(el => el.name === 'confirmEmail') &&
                                  emailExists &&
                                  !isLoggedIn && (
                                    <div className="email-registered-message">
                                      <p className="email-registered-text">
                                        ✓ This email is already registered. Log in to
                                        auto-fill your information
                                      </p>
                                      <Button
                                        type="button"
                                        variant="contained"
                                        className="email-login-button"
                                        onClick={() => {
                                          if (onLogin) {
                                            onLogin()
                                          } else {
                                            setShowModalLogin(true)
                                          }
                                        }}
                                      >
                                        Log in
                                      </Button>
                                    </div>
                                  )}
                              </React.Fragment>
                            )
                          })}
                        </div>
                      )
                    })}
                  {!_isEmpty(ticketHoldersFields.fields) && (
                    <div className="ticket-holders-fields">
                      <h2>{ticketHoldersFields.label}</h2>
                      {_map(ticketsQuantity, (_item, index) => (
                        <div key={_item}>
                          <h5>Ticket {index + 1}</h5>
                          {_map(ticketHoldersFields.fields, group => {
                            const { id, groupClassname, groupItems } = group
                            return (
                              <div key={id}>
                                <div className={groupClassname}>
                                  {_map(groupItems, element => (
                                    <div className={element.className} key={element.name}>
                                      <Field
                                        {...element}
                                        type={
                                          element.type === 'radio' ||
                                          element.type === 'checkbox'
                                            ? undefined
                                            : element.type
                                        }
                                        name={`${element.name}-${index}`}
                                        label={getFieldLabel(element, configs)}
                                        component={getFieldComponent(element)}
                                        validate={getValidateFunctions(
                                          element,
                                          states,
                                          props.values,
                                          props.errors
                                        )}
                                        setPhoneValidationIsLoading={
                                          setPhoneValidationIsLoading
                                        }
                                        fill={element.type === 'phone' ? true : undefined}
                                        defaultCountry={
                                          defaultCountry || element.defaultCountry
                                        }
                                        isCountryCodeEditable={isCountryCodeEditable}
                                      />
                                    </div>
                                  ))}
                                </div>
                              </div>
                            )
                          })}
                        </div>
                      ))}
                    </div>
                  )}
                  <div className="payment-section">
                    {isSinglePageCheckout && !orderIsFree && stripePublishableKey && (
                      <PaymentContainer
                        stripePublishableKey={stripePublishableKey}
                        stripeAccountId={stripeAccountId}
                        formTitle="Payment Information"
                        orderInfoLabel=""
                        enableTimer={false}
                        checkoutData={checkoutData}
                        elementsOptions={elementsOptions}
                        paymentElementOptions={{
                          fields: { billingDetails: { phone: 'never' } },
                          wallets: {
                            applePay:
                              checkoutUpdateData?.additional_payment_information
                                ?.stripe_wallets?.applePay || 'never',
                            googlePay:
                              checkoutUpdateData?.additional_payment_information
                                ?.stripe_wallets?.googlePay || 'never',
                          },
                        }}
                        onStripeReady={(stripe, elements) => {
                          stripeRef.current = stripe
                          elementsRef.current = elements
                        }}
                        paymentFields={paymentProps.paymentFields || []}
                        onPaymentError={paymentProps.onPaymentError || _identity}
                        handlePayment={paymentProps.handlePayment || _identity}
                        onGetPaymentDataSuccess={
                          paymentProps.onGetPaymentDataSuccess || _identity
                        }
                        onGetPaymentDataError={
                          paymentProps.onGetPaymentDataError || _identity
                        }
                        themeOptions={themeOptions}
                        paymentInfoLabel=""
                        displayPaymentButton={false}
                        hidePaymentForm={false}
                        hideFieldsBlock={true}
                        isSinglePageCheckout={true}
                      />
                    )}
                    {paymentSectionAddon}
                  </div>
                  <div className="button-container">
                    <Button
                      type="submit"
                      variant="contained"
                      className="login-register-button"
                      disabled={props.isSubmitting || phoneValidationIsLoading}
                    >
                      {props.isSubmitting ? (
                        <CircularProgress size={26} />
                      ) : orderIsFree ? (
                        freeOrderButtonName
                      ) : (
                        buttonName
                      )}
                    </Button>
                  </div>
                </div>
              </Form>
            )}
          </Formik>
        )}
        {showModalLogin && (
          <LoginModal
            logo={logo}
            onClose={() => {
              setShowModalLogin(false)
            }}
            onLogin={() => {
              setShowModalLogin(false)
              setUserExpired(false)
              onLoginSuccess()
            }}
            alreadyHasUser={alreadyHasUser}
            userExpired={userExpired}
            onGetProfileDataSuccess={(data: any) => {
              fetchCart()
              onGetProfileDataSuccess(data)
            }}
            onGetProfileDataError={onGetProfileDataError}
            showSignUpButton={showSignUpButton}
            showForgotPasswordButton={showForgotPasswordButton}
            onForgotPassword={() => {
              setShowModalLogin(false)
              setShowModalForgotPassword(true)
            }}
            onSignup={() => {
              setShowModalLogin(false)
              setShowModalSignup(true)
            }}
            showPoweredByImage={showPoweredByImage}
          />
        )}
        {showModalSignup && (
          <SignupModal
            onClose={() => {
              setShowModalSignup(false)
            }}
            onLogin={() => {
              setShowModalSignup(false)
              setShowModalLogin(true)
            }}
            onRegisterSuccess={onRegisterSuccess}
            onRegisterError={onRegisterError}
            showPoweredByImage={showPoweredByImage}
          />
        )}
        {showModalForgotPassword && (
          <ForgotPasswordModal
            onClose={() => {
              setShowModalForgotPassword(false)
            }}
            onLoginButtonClick={() => {
              setShowModalForgotPassword(false)
              setShowModalLogin(true)
            }}
            onForgotPasswordSuccess={onForgotPasswordSuccess}
            onForgotPasswordError={onForgotPasswordError}
            showPoweredByImage={showPoweredByImage}
            displaySuccessMessage
          />
        )}
        <VerificationPendingModal
          message={pendingVerificationMessage}
          onClose={() => {
            onPendingVerification()
          }}
        />
      </ThemeProvider>
    )
  }
)

const WithCustomFieldsBillingInfoContainer = withCustomFields(BillingInfoContainer)

export { WithCustomFieldsBillingInfoContainer as BillingInfoContainer }
