package pl.novelpay.samplesdkcommunicator

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tylerthrailkill.helpers.prettyprint.pp
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import pl.novelpay.client.core.Client
import pl.novelpay.client.sdk.interceptor.ClientInterceptor
import pl.novelpay.retailer.factory.RetailerMessageArguments
import pl.novelpay.retailer.message.payment.PaymentType
import pl.novelpay.retailer.message.response.ErrorRetailerLoginResponse
import pl.novelpay.retailer.message.response.SuccessRetailerLoginResponse
import pl.novelpay.retailer.message.response.SuccessRetailerLogoutResponse
import pl.novelpay.transport.converter.utls.RetailerAdminExtension
import pl.novelpay.util.domain.payment.PaymentAmounts
import pl.novelpay.util.domain.transactionStatus.MessageReference
import java.math.BigDecimal

class MainViewModel : ViewModel() {
    lateinit var clientSDK: Client

    private val _response: MutableStateFlow<String> = MutableStateFlow("")
    private val _saleReferenceId: MutableStateFlow<String> = MutableStateFlow("00-819")
    private val _transactionId: MutableStateFlow<String> = MutableStateFlow("00-819")

    private val _messageCategory: MutableStateFlow<String> = MutableStateFlow("Admin")

    // Admin
    private val _actionActivation: MutableStateFlow<String> = MutableStateFlow("Activation")
    private val _actionUpdate: MutableStateFlow<String> = MutableStateFlow("Update")
    private val _timeout: MutableStateFlow<Int> = MutableStateFlow(500000)

    // Payment
    private val _currency: MutableStateFlow<String> = MutableStateFlow("EUR")

    //Reversal
    private val _poiTransactionId: MutableStateFlow<String> = MutableStateFlow("12345")
    val poiTransactionId: StateFlow<String> = _poiTransactionId


    val _service = MutableStateFlow(SupportedPaymentServices.first())
    val service: StateFlow<String> = _service

    // Amounts
    private val _amount: MutableStateFlow<String> = MutableStateFlow("1.0")
    private val _cashBackAmount: MutableStateFlow<String?> = MutableStateFlow(null)
    private val _tipAmount: MutableStateFlow<String?> = MutableStateFlow(null)
    private val _paidAmount: MutableStateFlow<String?> = MutableStateFlow(null)

    // Public amounts
    val cashbackAmount: StateFlow<String?> = _cashBackAmount
    val tipAmount: StateFlow<String?> = _tipAmount
    val paidAmount: StateFlow<String?> = _paidAmount
    val amount: StateFlow<String> = _amount
    val currency: StateFlow<String> = _currency

    val response: StateFlow<String> = _response
    val interceptor = ClientInterceptor { message ->
        viewModelScope.launch {
            val builder = StringBuilder()
            message.pp(writeTo = builder)
            _response.emit(builder.toString())
        }
        when (message) {
            is SuccessRetailerLoginResponse -> {
                viewModelScope.launch { _response.emit("Success Login") }
            }

            is ErrorRetailerLoginResponse -> {
                viewModelScope.launch { _response.emit("Failed Login") }
            }

            is SuccessRetailerLogoutResponse -> {
                viewModelScope.launch { _response.emit("Success Logout") }
            }
        }
        Result.success(message)
    }

    fun switchPoiTransactionId(input: String) = viewModelScope.launch {
        _poiTransactionId.emit(input)
    }

    fun switchCurrency(input: String) = viewModelScope.launch {
        _currency.emit(input.toUpperCase().trim())
    }

    fun switchService(input: String) = viewModelScope.launch {
        if (input in SupportedPaymentServices)
            _service.emit(input)
    }

    fun switchAmount(input: String) = viewModelScope.launch {
        _amount.emit(input.replaceCommaWithDot())
    }

    fun switchPaidAmount(input: String) = viewModelScope.launch {
        _paidAmount.emit(input.replaceCommaWithDot())
    }

    fun switchTipAmount(input: String) = viewModelScope.launch {
        _tipAmount.emit(input.replaceCommaWithDot())
    }

    fun switchCashbackAmount(input: String) = viewModelScope.launch {
        _cashBackAmount.emit(input.replaceCommaWithDot())
    }

    fun sendLogin() {
        viewModelScope.launch {
            clientSDK.sendLoginRequest()
        }
    }

    fun sendLogout() {
        viewModelScope.launch {
            clientSDK.sendLogoutRequest()
        }
    }

    fun sendStatusRequest() {
        viewModelScope.launch {
            clientSDK.sendTransactionStatusRequest(
                MessageReference(_messageCategory.value)
            )
        }
    }

    fun sendActivationRequest() {
        viewModelScope.launch {
            clientSDK.sendAdminRequest(
                RetailerAdminExtension(
                    action = _actionActivation.value,
                    timeout = _timeout.value
                )
            )
        }
    }

    fun sendUpdateRequest() {
        viewModelScope.launch {
            clientSDK.sendAdminRequest(
                RetailerAdminExtension(
                    action = _actionUpdate.value,
                    timeout = _timeout.value
                )
            )
        }
    }

    fun sendTestConnectionRequest() {
        viewModelScope.launch {
            clientSDK.sendTestConnectionRequest(
                RetailerMessageArguments.DiagnosisRequestMessageArguments()
            )
        }
    }

    fun sendReversalRequest() {
        viewModelScope.launch {
            clientSDK.sendReversalRequest(
                saleReferenceId = _saleReferenceId.value,
                poiTransactionId = _poiTransactionId.value,
                transactionData = RetailerMessageArguments.ReversalRequestMessageArguments.TransactionAmountsData(
                    reversedAmount = _amount.value.toBigDecimalOrNull() ?: BigDecimal.ONE,
                    currency = _currency.value
                )
            )
        }
    }

    fun sendPayment() {
        viewModelScope.launch {
            clientSDK.sendPaymentRequest(
                saleReferenceId = _saleReferenceId.value,
                transactionID = _transactionId.value,
                paymentAmounts = PaymentAmounts(
                    currency = currency.value,
                    amount = amount.value.toBigDecimalOrNull() ?: BigDecimal.ONE,
                    cashbackAmount = cashbackAmount.value?.toBigDecimalOrNull(),
                    tipAmount = tipAmount.value?.toBigDecimalOrNull(),
                    paidAmount = paidAmount.value?.toBigDecimalOrNull(),
                ),
                paymentType = PaymentType.valueOf(service.value)
            )
        }
    }

    private fun String.replaceCommaWithDot() =
        this.replace(",", ".").trim()
}