Android. Kotlin. Запоминай код, который я тебе отправляю package ru.maxi.mobile.feature.delivery.order.ui

import android.app.Application
import android.net.Uri
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import ru.maxi.mobile.App
import ru.maxi.mobile.R
import ru.maxi.mobile.business.auth.UserAuthorizationUseCase
import ru.maxi.mobile.business.deeplinks.DeepLinkInteractor
import ru.maxi.mobile.business.delivery.CartInteractor
import ru.maxi.mobile.business.delivery.OrderInteractor
import ru.maxi.mobile.business.delivery.PromoCodeInteractor
import ru.maxi.mobile.core.data.LoadableData
import ru.maxi.mobile.core.data.Money
import ru.maxi.mobile.core.data.ValidError
import ru.maxi.mobile.core.data.emitError
import ru.maxi.mobile.core.data.emitLoading
import ru.maxi.mobile.core.data.emitSuccess
import ru.maxi.mobile.core.data.exception.BusinessLogicException
import ru.maxi.mobile.core.data.exception.BusinessLogicValidException
import ru.maxi.mobile.core.data.mapped
import ru.maxi.mobile.entity.delivery.cart.CartProduct
import ru.maxi.mobile.entity.delivery.order.MakeOrderFormData
import ru.maxi.mobile.entity.delivery.order.NoProductAction
import ru.maxi.mobile.entity.delivery.order.OrderAddressParameters
import ru.maxi.mobile.entity.delivery.order.OrderParameters
import ru.maxi.mobile.entity.delivery.order.OrderPaymentType
import ru.maxi.mobile.entity.delivery.order.PaymentStatus
import ru.maxi.mobile.entity.delivery.order.PaymentTypeBlockViewItem
import ru.maxi.mobile.entity.delivery.order.onlinepayment.OnlinePaymentFormType
import ru.maxi.mobile.feature.analytics.model.events.AnalyticsDeliveryEvent
import ru.maxi.mobile.feature.analytics.usecase.AnalyticsUseCase
import ru.maxi.mobile.feature.delivery.config.business.DeliveryConfigInteractor
import ru.maxi.mobile.feature.delivery.config.entity.PaymentType
import ru.maxi.mobile.feature.delivery.latestComments.model.Comment
import ru.maxi.mobile.feature.delivery.model.MakeOrderFieldsData
import ru.maxi.mobile.feature.delivery.model.MakeOrderFieldsData.Fields.Companion.defaultViewState
import ru.maxi.mobile.feature.sbp.model.SbpSourceType
import ru.maxi.mobile.repositories.deeplink.DeepLinkType
import ru.maxi.mobile.ui.delivery.order.MakeOrderPaymentTypeBlockActions
import ru.maxi.mobile.utils.extractPhoneNumber
import ru.maxi.mobile.utils.isValidEmail
import javax.inject.Inject

/**
 * [ViewModel] для функционала оформления заказа
 */
class MakeOrderViewModel @Inject constructor(
    private val analyticsUseCase: AnalyticsUseCase,
    private val userAuthorizationUseCase: UserAuthorizationUseCase,
    private val orderInteractor: OrderInteractor,
    private val cartInteractor: CartInteractor,
    private val promoCodeInteractor: PromoCodeInteractor,
    private val deepLinkInteractor: DeepLinkInteractor,
    private val deliveryConfigInteractor: DeliveryConfigInteractor,
) : AndroidViewModel(App.INSTANCE), MakeOrderPaymentTypeBlockActions {

    private var promoCode: String? = null
    private var cartProducts: List<CartProduct> = emptyList()
    private var isDataLoaded: Boolean = false

    /** События навигации */
    private val _navigationEvent = Channel<MakeOrderNavigationEvent>(Channel.BUFFERED)
    val navigationEvent = _navigationEvent.receiveAsFlow()

    /** События сообщений */
    private val _messageEvent = Channel<String>(Channel.BUFFERED)
    val messageEvent = _messageEvent.receiveAsFlow()

    private val paymentTypesFlow: StateFlow<List<OrderPaymentType>> by lazy {
        combine(
            flowOf(deliveryConfigInteractor.getPaymentTypeList()),
            orderInteractor.getOnlinePaymentCardListFlow(),
        ) { paymentTypes, cardList ->
            buildList {
                addAll(paymentTypes.map(PaymentType::toOrderPaymentType))

                val newCardOnlineTypeIndex = paymentTypes.indexOf(PaymentType.ONLINE)
                if (newCardOnlineTypeIndex >= 0) {
                    addAll(newCardOnlineTypeIndex, cardList.map(OrderPaymentType::ByCardOnline))
                }
            }
        }.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
    }

    private val selectedPaymentTypeFlow = MutableStateFlow<OrderPaymentType?>(null)

    private val loadingState = MutableStateFlow<LoadableData<Nothing?>>(LoadableData.Loading())

    val latestCommentsListState: StateFlow<List<Comment>?> = orderInteractor.getLatestCommentsListFlow()
        .onStart { Log.d("TESTING", "1 INIT latestCommentListState") }
        .stateIn(viewModelScope, SharingStarted.Lazily, null)

    val selectedLastCommentState: Flow<Comment?> = orderInteractor.getSelectedLastCommentFlow()
        .onStart { Log.d("TESTING", "2 INIT selectedLastCommentState") }
        .stateIn(viewModelScope, SharingStarted.Lazily, null)

    private val dataState = MutableStateFlow<MakeOrderFieldsData>(defaultViewState)
    private val requiredViewState get() = (dataState.value as MakeOrderFieldsData.Fields)

    private val viewState = combine(
        dataState,
        paymentTypesFlow,
        selectedPaymentTypeFlow,
    ) { state, paymentTypes, selectedPaymentType ->
        if (state is MakeOrderFieldsData.AnonymousUserData) return@combine MakeOrderFieldsData.AnonymousUserData

        (state as MakeOrderFieldsData.Fields).copy(
            paymentBlock = MakeOrderFieldsData.Fields.PaymentBlock(
                paymentTypes = paymentTypes.map {
                    PaymentTypeBlockViewItem(
                        paymentType = it,
                        isSelected = it == selectedPaymentType,
                    )
                },
                needShowMyCardsBtn = paymentTypes.any {
                    it is OrderPaymentType.ByCardOnline
                },
            ),
        )
    }

    /** Состояние полей оформления заказа */
    val fieldsState: Flow<LoadableData<MakeOrderFieldsData>> = viewState
        .combine(
            loadingState,
        ) { data, loadingData ->
            loadingData.mapped { data }
        }
        .onStart {
            loadData()
        }.stateIn(viewModelScope, SharingStarted.Lazily, LoadableData.Loading())

    /** Состояние ошибок полей заказа */
    val fieldsErrorsState: Flow<Set<MakeOrderFieldsData.Fields.FieldError>> = viewState
        .filterIsInstance<MakeOrderFieldsData.Fields>()
        .map { it.fieldsErrors }
        .stateIn(viewModelScope, SharingStarted.Lazily, emptySet())

    /**
     * Загрузить данные
     */
    fun loadData() {
        if (userAuthorizationUseCase.isUserAnonymous()) {
            orderInteractor.saveMakeOrderFields(MakeOrderFieldsData.AnonymousUserData)
            loadingState.emitSuccess(null)
            return
        }

        viewModelScope.launch {
            try {
                if (!isDataLoaded) {
                    initOrderData()
                }
            } catch (exception: Exception) {
                if (exception is BusinessLogicValidException && exception.code == ValidError.CART_MIN_SUM_NOT_REACHED) {
                    _navigationEvent.send(MakeOrderNavigationEvent.ShowErrorMinSaveDialog(exception.message))
                } else {
                    loadingState.emitError(exception)
                }
            }
        }
    }

    private suspend fun initOrderData() {
        if (!orderInteractor.getAddressSelected()) {
            _navigationEvent.trySend(MakeOrderNavigationEvent.OpenMapIntervalsAddresses)
            return
        }
        val cacheOrderData = orderInteractor.makeOrderFieldsData.first() as MakeOrderFieldsData.Fields
        val phone = cacheOrderData.contactsBlock.phone.let {
            it.ifEmpty {
                orderInteractor.getUserPhone()
            }
        }

        if (deliveryConfigInteractor.getPaymentTypeList().contains(PaymentType.ONLINE)) {
            orderInteractor.loadOnlinePaymentCardList()
        }
        val orderInitData = orderInteractor.getInitData()
        val email = cacheOrderData.orderInitData?.email ?: orderInitData.email
        promoCode = promoCodeInteractor.getPromoCode()?.data?.text

        val cartProducts = cartInteractor.getProductList()
        analyticsUseCase log AnalyticsDeliveryEvent.BeginCheckout(
            cartProducts = cartProducts,
            orderAmount = orderInitData.orderSum,
            hasClientAddress = orderInitData.clientAddress != null,
            promoCode = promoCode,
            promoCodeDiscount = orderInitData.promoCodeDiscount,
        )

        val bonusesAmount = Money.fromWholePart(orderInitData.bonusesPointsDiscount?.toLong() ?: 0)
        val promoCodeDiscount = orderInitData.promoCodeDiscount ?: Money.ZERO
        val totalAmount = with(orderInitData) {
            (orderSum + deliveryPrice + (weightData.overWeightData?.overWeightAmount ?: Money.ZERO)) -
                (bonusesAmount + promoCodeDiscount)
        }

        val newFieldsData = cacheOrderData.copy(
            contactsBlock = MakeOrderFieldsData.Fields.ContactsBlock(
                cacheOrderData.contactsBlock.name,
                phone,
            ),
            orderInitData = orderInitData.copy(email = email),
            summaryBlock = MakeOrderFieldsData.Fields.SummaryBlock(
                orderAmount = orderInitData.orderSum,
                deliveryAmount = orderInitData.deliveryPrice,
                bonusesAmount = bonusesAmount,
                promoCodeDiscountAmount = promoCodeDiscount,
                totalAmount = totalAmount,
                weightData = orderInitData.weightData,
            ),
        )
        dataState.emit(newFieldsData)
        isDataLoaded = true
        loadingState.emitSuccess(null)
    }

    /**
     * Обработать изменение текста [text] в поле email'а
     */
    fun onEmailTextChanged(text: String) {
        val email = text.trimStart()
        if (requiredViewState.orderInitData?.email == email) return

        dataState.update { _ ->
            requiredViewState.copy(
                orderInitData = requiredViewState.orderInitData?.copy(email = email),
                fieldsErrors = requiredViewState.fieldsErrors - setOf(
                    emailNotValidError,
                    emailNotFilledError,
                ),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле номера телефона
     */
    fun onPhoneTextChanged(text: String) {
        val phone = text.trimStart()
        if (requiredViewState.contactsBlock.phone == phone) return

        dataState.update { _ ->
            requiredViewState.copy(
                contactsBlock = requiredViewState.contactsBlock.copy(phone = phone),
                fieldsErrors = requiredViewState.fieldsErrors - setOf(phoneNotFilledError, phoneNotValidError),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле имени клиента
     */
    fun onNameTextChanged(text: String) {
        val name = text.trimStart()
        if (requiredViewState.contactsBlock.name == name) return

        dataState.update { _ ->
            requiredViewState.copy(
                contactsBlock = requiredViewState.contactsBlock.copy(name = name),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле квартиры клиента
     */
    fun onApartmentTextChanged(text: String) {
        val apartment = text.trimStart()
        if (requiredViewState.customAddressBlock.apartment == apartment) return

        dataState.update { _ ->
            requiredViewState.copy(
                customAddressBlock = requiredViewState.customAddressBlock.copy(apartment = apartment),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле подъезда клиента
     */
    fun onEntranceTextChanged(text: String) {
        val entrance = text.trimStart()
        if (requiredViewState.customAddressBlock.entrance == entrance) return

        dataState.update { _ ->
            requiredViewState.copy(
                customAddressBlock = requiredViewState.customAddressBlock.copy(entrance = entrance),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле этажа клиента
     */
    fun onFloorTextChanged(text: String) {
        val floor = text.trimStart()
        if (requiredViewState.customAddressBlock.floor == floor) return

        dataState.update { _ ->
            requiredViewState.copy(
                customAddressBlock = requiredViewState.customAddressBlock.copy(floor = floor),
            )
        }
    }

    /**
     * Обработать изменение текста [text] в поле комментария к заказу
     */
    fun onCommentTextChanged(text: String) {
        val comment = text.trimStart()
        if (requiredViewState.comment == comment) return

        dataState.update { _ ->
            requiredViewState.copy(
                comment = comment,
            )
        }
    }

    /**
     * Обработать клик по кнопке оформления заказа
     */
    fun onMakeOrderButtonClick(allowEmptyAddressFields: Boolean = false) {
        val formData = MakeOrderFormData(
            name = requiredViewState.contactsBlock.name.trim(),
            phone = requiredViewState.contactsBlock.phone.extractPhoneNumber(),
            apartment = requiredViewState.customAddressBlock.apartment,
            entrance = requiredViewState.customAddressBlock.entrance.toIntOrNull(),
            floor = requiredViewState.customAddressBlock.floor.toIntOrNull(),
            comment = requiredViewState.comment,
            email = requiredViewState.orderInitData?.email.toString(),
        )

        if (!validateFormData(formData, allowEmptyAddressFields)) return

        val orderParameters = createOrderParameters(formData)
        viewModelScope.launch {
            try {
                loadingState.emitLoading()

                val createdOrder = orderInteractor.sendOrder(orderParameters)
                val deliveryPrice = requiredViewState.orderInitData?.deliveryPrice?.plus(
                    (requiredViewState.orderInitData?.weightData?.overWeightData?.overWeightAmount ?: Money.ZERO),
                )

                promoCodeInteractor.clearPushPromoCode()
                analyticsUseCase log AnalyticsDeliveryEvent.Purchase(
                    createdOrder.id,
                    cartProducts,
                    orderAmount = requiredViewState.orderInitData?.orderSum ?: Money.ZERO,
                    deliveryAmount = deliveryPrice ?: Money.ZERO,
                    promoCode,
                    requiredViewState.orderInitData?.promoCodeDiscount,
                )

                dataState.emit(defaultViewState)
                if (createdOrder.paymentInfo.status == PaymentStatus.WAITING) {
                    processPayment(createdOrder.id)
                } else {
                    finishAndOpenOrderList(createdOrder.id)
                }
            } catch (exception: Exception) {
                val errorMessage = (exception as? BusinessLogicException)?.message
                    ?: exception.localizedMessage
                _messageEvent.send(errorMessage)
                loadingState.emitSuccess(null)
            }
        }
    }

    private fun createOrderParameters(formData: MakeOrderFormData): OrderParameters {
        val orderAddress = OrderAddressParameters(
            apartment = formData.apartment,
            entrance = formData.entrance,
            floor = formData.floor,
        )
        return OrderParameters(
            orderAddress = orderAddress,
            name = formData.name,
            phone = formData.phone,
            noProductAction = requiredViewState.noProductAction!!,
            comment = formData.comment,
            paymentType = requireNotNull(selectedPaymentTypeFlow.value),
            bonusesCount = requiredViewState.orderInitData?.bonusesPointsDiscount,
            email = formData.email,
        )
    }

    private fun validateFormData(data: MakeOrderFormData, allowEmptyAddressFields: Boolean): Boolean {
        dataState.update { _ ->
            requiredViewState.copy(
                fieldsErrors = when {
                    data.phone.isBlank() -> requiredViewState.fieldsErrors + phoneNotFilledError - phoneNotValidError
                    data.phone.length < 10 -> requiredViewState.fieldsErrors + phoneNotValidError - phoneNotFilledError
                    else -> requiredViewState.fieldsErrors - setOf(phoneNotFilledError, phoneNotValidError)
                },
            )
        }

        if (requiredViewState.fieldsErrors.isNotEmpty()) {
            return false
        }

        if (requiredViewState.orderInitData?.clientAddress == null &&
            !allowEmptyAddressFields &&
            data.apartment.isNullOrBlank() &&
            data.entrance == null &&
            data.floor == null
        ) {
            _navigationEvent.trySend(MakeOrderNavigationEvent.ShowEmptyFieldsErrorDialog)
            return false
        }

        if (requiredViewState.noProductAction == null) {
            _messageEvent.trySend(
                getApplication<Application>().getString(R.string.delivery_makeorder_no_product_action_empty_error),
            )
            return false
        }

        if (selectedPaymentTypeFlow.value == null) {
            _messageEvent.trySend(
                getApplication<Application>().getString(R.string.delivery_makeorder_no_payment_type_selected),
            )
            return false
        }

        val email = requiredViewState.orderInitData?.email ?: return false
        dataState.update { _ ->
            requiredViewState.copy(
                fieldsErrors = when {
                    email.isBlank() -> requiredViewState.fieldsErrors - emailNotValidError + emailNotFilledError
                    !email.isValidEmail() -> requiredViewState.fieldsErrors + emailNotValidError - emailNotFilledError
                    else -> requiredViewState.fieldsErrors - emailNotValidError - emailNotFilledError
                },
            )
        }

        return requiredViewState.fieldsErrors.isEmpty()
    }

    /**
     * Обработать клик по кнопке выбора действия в случае отсутствия заказа
     */
    fun onNoProductActionChange(action: NoProductAction) {
        dataState.tryEmit(
            requiredViewState.copy(
                noProductAction = action,
            ),
        )
    }

    /**
     * Обработать клик по кнопке перехода на условия оферты
     */
    fun onOfferClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenOfferRules)
    }

    /**
     * Обработать клик по кнопке перехода на условия обработки персональных данных
     */
    fun onPersonalDataClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenPersonalDataRules)
    }

    /**
     * Обработать клик на выбор карты для онлайн оплаты
     */
    fun onOnlinePaymentChooseCardClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenOnlinePaymentChooseCard)
    }

    /**
     * Обработать клик по кнопке авторизации
     */
    fun onAuthButtonClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenAuth)
    }

    /**
     * Обработать клик по кнопке перехода на экран помощи
     */
    fun onGoToFaqClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenFaqScreen)
    }

    /**
     * Обработать клик по кнопке изменения адреса и интервала
     */
    fun onChangeAddressIntervalClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.ShowChangeAddressIntervalDialog)
    }

    /**
     * Обработать клик по подтверждению изменения адреса и интервала в диалоге
     */
    fun onConfirmChangeAddressInterval() {
        orderInteractor.saveMakeOrderFields(dataState.value)
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenMapIntervalsAddresses)
    }

    /**
     * Обработать изменение адреса и интервала
     */
    fun onChangeAddressInterval() {
        if (isDataLoaded) {
            loadOnlineClientAddress()
        } else {
            loadData()
        }
    }

    /**
     * Обработать клик по кнопке "Подробные условия"
     */
    fun onOverWeightConditionsClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenOverWeightConditions)
    }

    /**
     * Обработать клик по кнопке "Последние комментарии"
     */
    fun onLatestCommentsButtonClick() {
        _navigationEvent.trySend(MakeOrderNavigationEvent.OpenLatestCommentsChooserScreen)
    }

    override fun onPaymentTypeClick(position: Int) {
        val paymentType = paymentTypesFlow.value[position]
        viewModelScope.launch {
            try {
                when (paymentType) {
                    OrderPaymentType.ByNewCardOnline -> {
                        selectedPaymentTypeFlow.update { null }
                        val addCardData = orderInteractor.addOnlinePaymentCard()
                        val paymentData = addCardData.copy(
                            formType = OnlinePaymentFormType.AddNewCard(),
                        )
                        _navigationEvent.send(
                            MakeOrderNavigationEvent.OpenOnlinePaymentForm(
                                paymentData,
                                OnlinePaymentFormType.AddNewCard.ADD_NEW_CARD_REQUEST_KEY,
                            ),
                        )
                    }

                    else -> selectedPaymentTypeFlow.update { paymentType }
                }
            } catch (exception: Exception) {
                val errorMessage = (exception as? BusinessLogicException)?.message
                    ?: exception.localizedMessage
                _messageEvent.send(errorMessage)
            }
        }
    }

    private suspend fun processPayment(orderId: Long) {
        try {
            val onlinePaymentType = checkNotNull(selectedPaymentTypeFlow.value)
            val paymentFormType = OnlinePaymentFormType.OrderPayment(orderId)
            val paymentData = orderInteractor.startOrderOnlinePayment(orderId)
                .copy(formType = paymentFormType)
            when (onlinePaymentType) {
                OrderPaymentType.ViaSbp -> {
                    parseSbpQrContent(
                        paymentData.formUrl,
                        paymentFormType.resultRequestKey,
                        orderId,
                        requireNotNull(paymentData.merchantName),
                    )
                }

                is OrderPaymentType.ByCardOnline -> {
                    _navigationEvent.send(
                        MakeOrderNavigationEvent.OpenOnlinePaymentForm(
                            paymentData,
                            paymentFormType.resultRequestKey,
                        ),
                    )
                }

                else -> throw BusinessLogicException("Invalid payment type")
            }
        } catch (ignored: Exception) {
            finishAndOpenOrderList(orderId)
        }
    }

    private fun parseSbpQrContent(qrContent: String, resultKey: String, orderId: Long, merchantName: String) {
        try {
            val uri = Uri.parse(qrContent)
            check(uri.isHierarchical && uri.host == "qr.nspk.ru")
            _navigationEvent.trySend(
                MakeOrderNavigationEvent.OpenBankChooserScreen(
                    paymentUri = uri,
                    sbpSourceType = SbpSourceType.QR,
                    resultKey = resultKey,
                    onBankChooserResult = { finishAndOpenOrderList(orderId) },
                    merchantName = merchantName,
                ),
            )
        } catch (ignored: Exception) {
            finishAndOpenOrderList(orderId)
        }
    }

    /**
     * Закрыть текущий экран и перейти на список заказов
     */
    fun finishAndOpenOrderList(newOrderId: Long) {
        deepLinkInteractor.saveDeepLink(DeepLinkType.OpenOrderList(newOrderId = newOrderId))
        _navigationEvent.trySend(MakeOrderNavigationEvent.Exit)
    }

    /**
     * Обновить информацию об оплате заказа
     */
    fun loadOnlinePaymentCardList() {
        viewModelScope.launch {
            try {
                loadingState.emitLoading()
                if (deliveryConfigInteractor.getPaymentTypeList().contains(PaymentType.ONLINE)) {
                    orderInteractor.loadOnlinePaymentCardList()
                }
                loadingState.emitSuccess(null)
            } catch (exception: Exception) {
                _messageEvent.send(exception.localizedMessage!!)
            }
        }
    }

    private fun loadOnlineClientAddress() {
        viewModelScope.launch {
            try {
                loadingState.emitLoading()
                val cacheOrderData = orderInteractor.makeOrderFieldsData.first() as MakeOrderFieldsData.Fields
                val orderInitData = orderInteractor.getInitData()
                val email = cacheOrderData.orderInitData?.email ?: orderInitData.email
                promoCode = promoCodeInteractor.getPromoCode()?.data?.text

                val bonusesAmount = Money.fromWholePart(orderInitData.bonusesPointsDiscount?.toLong() ?: 0)
                val promoCodeDiscount = orderInitData.promoCodeDiscount ?: Money.ZERO
                val totalAmount = with(orderInitData) {
                    (orderSum + deliveryPrice + (weightData.overWeightData?.overWeightAmount ?: Money.ZERO)) -
                        (bonusesAmount + promoCodeDiscount)
                }

                dataState.emit(
                    requiredViewState.copy(
                        customAddressBlock = cacheOrderData.customAddressBlock,
                        orderInitData = orderInitData.copy(email = email),
                        summaryBlock = MakeOrderFieldsData.Fields.SummaryBlock(
                            orderAmount = orderInitData.orderSum,
                            deliveryAmount = orderInitData.deliveryPrice,
                            bonusesAmount = bonusesAmount,
                            promoCodeDiscountAmount = promoCodeDiscount,
                            totalAmount = totalAmount,
                            weightData = orderInitData.weightData,
                        ),
                    ),
                )

                loadingState.emitSuccess(null)
            } catch (exception: Exception) {
                loadingState.emitError(exception)
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        orderInteractor.saveMakeOrderFields(dataState.value)
    }

    private companion object {

        val emailNotValidError = MakeOrderFieldsData.Fields.FieldError.EmailNotValid
        val emailNotFilledError = MakeOrderFieldsData.Fields.FieldError.EmailNotFilled

        val phoneNotValidError = MakeOrderFieldsData.Fields.FieldError.PhoneNotValid
        val phoneNotFilledError = MakeOrderFieldsData.Fields.FieldError.PhoneNotFilled
    }
}

private fun PaymentType.toOrderPaymentType(): OrderPaymentType {
    return when (this) {
        PaymentType.CASH -> OrderPaymentType.Cash
        PaymentType.CARD -> OrderPaymentType.ByCard
        PaymentType.ONLINE -> OrderPaymentType.ByNewCardOnline
        PaymentType.SBP -> OrderPaymentType.ViaSbp
    }
}