package uz.mobiuz.mobiservice.dev.ui.sdk.payment

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.method.DigitsKeyListener
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import com.google.gson.Gson
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.fragment_replenish_balance.*
import kotlinx.coroutines.flow.collect
import uz.agr.sdk.core.entity.card.CardInfo
import uz.agr.sdk.core.entity.tuple.Tuple3
import uz.agr.sdk.coreui.extension.hideSoftInput
import uz.agr.sdk.coreui.extension.showSnackMessage
import uz.agr.sdk.coreui.ui.form.AmountFormat
import uz.agr.sdk.coreui.ui.form.CardDateExpireFormat
import uz.agr.sdk.coreui.ui.form.CardNumberFormat
import uz.agr.sdk.mobi_uz.AGRBilling
import uz.agr.sdk.mobi_uz.BaseListener
import uz.agr.sdk.mobi_uz.CardListener
import uz.agr.sdk.mobi_uz.VendorPayConfirm
import uz.mobiuz.mobiservice.dev.R
import uz.mobiuz.mobiservice.dev.databinding.FragmentReplenishBalanceBinding
import uz.mobiuz.mobiservice.dev.model.Monitoring
import uz.mobiuz.mobiservice.dev.model.SharedPref
import uz.mobiuz.mobiservice.dev.network.model.UiStateObject
import uz.mobiuz.mobiservice.dev.ui.base.BaseFragment
import uz.mobiuz.mobiservice.dev.ui.global.ButtonClick
import uz.mobiuz.mobiservice.dev.ui.global.CONSTANTS
import uz.mobiuz.mobiservice.dev.ui.sdk.card.CardViewModel
import uz.mobiuz.mobiservice.dev.ui.sdk.pay.SelectAnotherCard
import uz.mobiuz.mobiservice.dev.utils.extensions.checkChangedPosition
import uz.mobiuz.mobiservice.dev.utils.extensions.customLog
import uz.mobiuz.mobiservice.dev.utils.extensions.maskedTextMobi
import java.util.*
import javax.inject.Inject
import kotlin.collections.HashMap

@AndroidEntryPoint
class ReplenishBalanceFragment : BaseFragment(R.layout.fragment_replenish_balance) {

    @Inject
    lateinit var pref: SharedPref

    private var _bn: FragmentReplenishBalanceBinding? = null
    private val bn get() = _bn ?: throw NullPointerException("cannot inflate")
    private val viewModel: CardViewModel by viewModels()
    private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { NavHostFragment.findNavController(this) }

    private var payWithAnotherCard = false
    private var selectedCard: CardInfo? = null

    private var amountIsValid = false
    private var amountValid: Long? = null

    private var cardNumberIsValid = false
    private var cardExpiryIsValid = false

    private var cardNumberValid: String = ""
    private var cardExpiryValid: String = ""
    private var phoneNumber = ""
    var oldText = ""
    var newText = ""

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        _bn = FragmentReplenishBalanceBinding.bind(view)

        setUpUI()
        collects()
    }

    override fun setUpUI() {

        getAllCards()
        initPhone()
        initInputAmount()
        initInputCardNumber()
        initInputCardExpiry()


        bn.apply {
            toolbar.setNavigationOnClickListener {
                navController.navigateUp()
            }

            etAmountInterval.text = getString(R.string.agr_mobi_uz_amount_interval, "1000", "500 000")

            tvLinkOferta.setOnClickListener(object : uz.agr.sdk.coreui.ui.ButtonClick() {
                override fun onSingleClick(v: View?) {
                    val uri = Uri.parse(
                        when (pref.language) {
                            CONSTANTS.UZ -> CONSTANTS.PAYSYS_LICENSE_UZ
                            CONSTANTS.RU -> CONSTANTS.PAYSYS_LICENSE_RU
                            else -> CONSTANTS.PAYSYS_LICENSE_EN
                        }
                    )
                    val intent = Intent(Intent.ACTION_VIEW)
                    intent.data = uri
                    startActivity(intent)
                }
            })

            addCard.setOnClickListener(object : ButtonClick() {
                override fun onSingleClick(v: View?) {
                    onCLickAddCard()
                }
            })

            btnPay.setOnClickListener(object : ButtonClick() {
                override fun onSingleClick(v: View?) {
                    onClickPay()
                }
            })
        }
    }


    override fun collects() {
        viewLifecycleOwner.lifecycleScope.launchWhenCreated {
            viewModel.onClickedCardUiState.collect {
                when (it) {
                    is UiStateObject.SUCCESS -> {
                        bn.apply {
                            selectedCard = null
                            payWithAnotherCard = true
                            selectCardView.showNewCard()
                            selectCardView.isVisible = payWithAnotherCard
                            addCardForm.isVisible = payWithAnotherCard
                            customLog("addCard.isVisible = !payWithAnotherCard   ${!payWithAnotherCard}")
                            addCard.isVisible = !payWithAnotherCard
                            checkValidForm()
                            customLog("onClickedCardUiState")
                        }
                    }
                    else -> Unit
                }
            }
        }
    }

    private fun setCardListAdapter(list: List<CardInfo>) {
        bn.apply {
            initSelectCardView(list)
            customLog("addCard.isVisible = list.isEmpty()  ${list.isEmpty()}")
            if (!payWithAnotherCard) {
                addCard.isVisible = list.isEmpty()
                selectCardView.isVisible = list.isNotEmpty()
            }
            if (list.isNotEmpty()) {
                selectCardView.showCard(list[0], 0)
            }
        }
    }

    private fun initSelectCardView(list: List<CardInfo>) {
        bn.apply {
            selectCardView.init {
                requireActivity().hideSoftInput()
                val dialog = SelectCardBottomDialogFragment(cards = list)
                dialog.setListener(object : SelectCardBottomDialogFragment.Listener {
                    override fun onClickAnotherCard() {
                        selectedCard = null
                        payWithAnotherCard = true
                        selectCardView.showNewCard()
                        checkValidForm()
                        addCardForm.isVisible = payWithAnotherCard
                        checkValidForm()
                        dialog.dismiss()
                    }

                    override fun onClickCancel() {
                        dialog.dismiss()
                    }

                    override fun onClickCardSelected(cardInfo: CardInfo, position: Int) {
                        payWithAnotherCard = false
                        selectCardView.showCard(cardInfo, position)
                        addCardForm.isVisible = payWithAnotherCard
                        etCardNumber.text?.clear()
                        etCardExpiry.text?.clear()
                        tvErrorMsg.isVisible = false
                        tvErrorMsgExpiry.isVisible = false
                        showSelectedCard(cardInfo, position)
                        checkValidForm()
                        dialog.dismiss()
                    }
                })
                dialog.show(childFragmentManager, SelectCardBottomDialogFragment::class.java.simpleName)
            }
        }
    }

    private fun getAllCards() {
        AGRBilling.getAllCards(object : CardListener<CardInfo> {
            override fun error(message: String) {}
            override fun loading(boolean: Boolean) {}
            override fun local(localData: List<CardInfo>) {
                setCardListAdapter(localData)
                if (localData.isNotEmpty()) {
                    showSelectedCard(localData.first(), 0)
                }
            }

            override fun server(serverData: List<CardInfo>) {
                setCardListAdapter(serverData)
                if (serverData.isNotEmpty()) {
                    showSelectedCard(serverData.first(), 0)
                }
            }
        })
    }

    private fun showSelectedCard(cardInfo: CardInfo, position: Int) {
        bn.apply {
            selectedCard = cardInfo
            payWithAnotherCard = false
            selectCardView.showCard(cardInfo, position)
            checkValidForm()
        }
    }

    private fun onClickPay() {
        bn.apply {
            requireActivity().hideSoftInput()
            if (payWithAnotherCard) {
                pay()
            } else {
                if (selectedCard != null) {
                    if (selectedCard!!.balance > amountValid!!) pay()
                    else showSnackMessage(getString(R.string.agr_mobi_uz_not_enough_money))
                }
            }
        }
    }

    private fun isMobiUz(code: String): Boolean {
        return code == "97" || code == "88"
    }

    private fun pay() {
        bn.apply {
            val amount = amountValid ?: 0
            if (!isMobiUz(phoneNumber.substring(3, 5))) {
                showSnackMessage(getString(R.string.agr_mobi_uz_payment_phone_error))
                return
            }

            val vendorFormParams = HashMap<String, String>()
            val newAccount = phoneNumber.substring(3, phoneNumber.length).trim()

            val newType = phoneNumber.substring(3, 5)
            val type = getNewVendorId(newType.toInt())
            if (newType.toInt() == 99 || newType.toInt() == 95 || newType.toInt() == 71 || newType.toInt() == 97 || newType.toInt() == 88)
                vendorFormParams["amount"] = amount.toString()
            else vendorFormParams["summa"] = amount.toString()

            vendorFormParams["vendor_id"] = type.first.toString()
            if (newType.toInt() == 71) {
                vendorFormParams["type"] = "1"
            }
            if (newType.toInt() == 99 || newType.toInt() == 95 || newType.toInt() == 71) {
                vendorFormParams["account"] = newAccount
            } else {
                if (newType.toInt() == 90 || newType.toInt() == 91) vendorFormParams["phone_number"] = newAccount
                else vendorFormParams["clientid"] = newAccount
            }

            AGRBilling.vendorFormCheck(vendorFormParams, object : BaseListener<Boolean> {
                override fun error(message: String) {
                    showSnackMessage(message)
                }

                override fun loading(boolean: Boolean) {
                    showProgressDialog(boolean)
                }

                override fun success(data: Boolean) {
                    if (payWithAnotherCard) payWithAnotherCard(
                        cardNumberValid, cardExpiryValid, btnSwitch.isChecked, phoneNumber, vendorFormParams)
                    else vendorPay(selectedCard, pref.userPhone.filter { it.isDigit() }, vendorFormParams)
                }
            })
        }
    }

    private fun vendorPay(selectedCard: CardInfo?, phoneNumber: String, vendorFormParams: HashMap<String, String>) {
        if (selectedCard != null) {

            AGRBilling.onClickPay(phoneNumber, selectedCard, vendorFormParams, requireContext(), object : VendorPayConfirm {
                override fun showConfirmPage(transactionId: Long, phoneNumber: String, timeOut: Int) {

                    val monitoring = Monitoring(
                        date = System.currentTimeMillis(),
                        phone = this@ReplenishBalanceFragment.phoneNumber,
                        amount = bn.etAmount.text.toString().filter { it.isDigit() }.toLong(),
                        pan = selectedCard.pan
                    )
                    navController.navigate(
                        R.id.verificationFragment,
                        bundleOf(
                            CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ANOTHER_CARD,
                            CONSTANTS.PHONE to monitoring.phone,
                            CONSTANTS.PAY_AMOUNT to monitoring.amount,
                            CONSTANTS.TRANSACTION_ID to transactionId,
                            CONSTANTS.PAY_MONITORING to Gson().toJson(monitoring)
                        )
                    )
                }

                override fun showError(message: String) {
                    showSnackMessage(message)
                }

                override fun showProgress(show: Boolean) {
                    showProgressDialog(show)
                }

                override fun showSuccessfulPayment(transactionId: Long) {
                    val monitoring = Monitoring(
                        date = System.currentTimeMillis(),
                        phone = this@ReplenishBalanceFragment.phoneNumber,
                        amount = etAmount.text.toString().filter { it.isDigit() }.toLong(),
                        pan = selectedCard.pan
                    )
                    navController.navigate(
                        R.id.paymentSuccessfulFragment,
                        bundleOf(
                            CONSTANTS.PAY_MONITORING to Gson().toJson(monitoring)
                        )
                    )
                }
            })
        }
    }

    private fun payWithAnotherCard(cardNumber: String, cardExpiry: String, saveCard: Boolean, phone: String, vendorFormParams: HashMap<String, String>) {

        AGRBilling.vendorPayWithAnotherCard(cardNumber, cardExpiry, saveCard, phone, vendorFormParams, object : VendorPayConfirm {
            override fun showConfirmPage(transactionId: Long, phoneNumber: String, timeOut: Int) {
                var isSave = false
                val responsePhone = phoneNumber.replace("+", "")
                val inputPhone = phone.replace("+", "")
                isSave = responsePhone.substring(0, 5) == inputPhone.substring(0, 5) &&
                        responsePhone.substring(responsePhone.length - 2, responsePhone.length) == inputPhone.substring(inputPhone.length - 2, inputPhone.length)


                val monitoring = Monitoring(
                    date = System.currentTimeMillis(),
                    phone = this@ReplenishBalanceFragment.phoneNumber,
                    amount = etAmount.text.toString().filter { it.isDigit() }.toLong(),
                    pan = cardNumber
                )
                val isSaveCard = 0
                if (saveCard){
                    if (isSave) CONSTANTS.IS_SAVED_CARD else CONSTANTS.IS_NOT_SAVED_CARD
                }


                navController.navigate(
                    R.id.verificationFragment,
                    bundleOf(
                        CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ANOTHER_CARD,
                        CONSTANTS.TRANSACTION_ID to transactionId,
                        CONSTANTS.PHONE to phoneNumber,
                        CONSTANTS.PAY_AMOUNT to monitoring.amount,
                        CONSTANTS.SAVED_CARD to isSaveCard,
                        CONSTANTS.PAY_CARD_NUMBER to if (isSave) cardNumber else cardNumber + cardExpiry,
                        CONSTANTS.PAY_MONITORING to Gson().toJson(monitoring)
                    )
                )
            }

            override fun showError(message: String) {
                showSnackMessage(message)
            }

            override fun showProgress(show: Boolean) {
                showProgressDialog(show)
            }

            override fun showSuccessfulPayment(transactionId: Long) {
                val monitoring = Monitoring(
                    date = System.currentTimeMillis(),
                    phone = this@ReplenishBalanceFragment.phoneNumber,
                    amount = etAmount.text.toString().filter { it.isDigit() }.toLong(),
                    pan = cardNumber
                )

                navController.navigate(
                    R.id.paymentSuccessfulFragment,
                    bundleOf(
                        CONSTANTS.PAY_MONITORING to Gson().toJson(monitoring),
                        CONSTANTS.PAY_SAVE_CARD to if (saveCard) CONSTANTS.IS_SAVED_CARD else CONSTANTS.IS_NOT_SAVED_CARD,
                        CONSTANTS.PAY_CARD_NUMBER to cardNumber
                    )
                )
            }
        })
    }

    private fun onCLickAddCard() {
        requireActivity().hideSoftInput()
        val dialog = SelectAnotherCard()
        dialog.setListener(object : SelectAnotherCard.Listener {
            override fun onClickAnotherCard() {
                dialog.dismiss()
                viewModel.onCLickAddCard(System.currentTimeMillis())
            }

            override fun onClickAddCard() {
                navController.navigate(R.id.addCardFragment)
            }
        })
        dialog.show(childFragmentManager, SelectAnotherCard::class.java.simpleName)
    }

    private fun initPhone() {
        bn.apply {

            inputPhone.addTextChangedListener(object : uz.mobiuz.mobiservice.dev.ui.global.TextWatcherWrapper() {
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                    super.beforeTextChanged(s, start, count, after)
                    oldText = s.toString()
                }

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    super.onTextChanged(s, start, before, count)
                    try {
                        inputPhone.removeTextChangedListener(this)
                        val text = s.toString()
                        if (text.length < 5) {
                            inputPhone.setText("+998 ")
                            inputPhone.setSelection(5)
                        } else {
                            newText = text.filter { it.isDigit() || it == '+' }.maskedTextMobi()
                            inputPhone.setText(newText)
                            inputPhone.setSelection(oldText.checkChangedPosition(newText))

                        }
                        inputPhone.addTextChangedListener(this)
                        phoneNumber = inputPhone.text.toString().filter { it.isDigit() }
                    } catch (e: Exception) {
                        inputPhone.text.clear()
                        inputPhone.addTextChangedListener(this)
                    }

                }

                override fun afterTextChanged(s: Editable) {
                    val isAllFormsValid = if (amountValid != null && amountValid!! >= CONSTANTS.PAY_MIN_AMOUNT && amountValid!! <= CONSTANTS.PAY_MAX_AMOUNT)
                        amountIsValid && phoneNumber.length == 12
                    else false

                    val cardValid = if (payWithAnotherCard) cardNumberIsValid && cardExpiryIsValid else selectedCard != null

                    btnPay.isEnabled = isAllFormsValid && cardValid
                }
            })
        }
    }

    private fun initInputAmount() {
        bn.apply {
            etAmount.keyListener = DigitsKeyListener.getInstance("1234567890 ")
            etAmount.addTextChangedListener(AmountFormat { valid, amount ->
                amountIsValid = valid
                amountValid = amount
                checkValidForm()
            })
        }
    }

    private fun initInputCardNumber() {
        bn.apply {
            etCardNumber.keyListener = DigitsKeyListener.getInstance("1234567890 ")
            etCardNumber.addTextChangedListener(CardNumberFormat { valid, number ->
                cardNumberIsValid = valid
                if (valid) {
                    etCardExpiry.requestFocus()
                    cardNumberValid = number
                }
                tvErrorMsg.isVisible = !valid

                checkValidForm()
                if (etCardNumber.text.toString().isEmpty()) {
                    tvErrorMsg.isVisible = false
                }
            })
        }
    }

    private fun initInputCardExpiry() {
        bn.apply {
            etCardExpiry.keyListener = DigitsKeyListener.getInstance("1234567890/")
            etCardExpiry.addTextChangedListener(CardDateExpireFormat { valid, date ->
                var checkValid = valid
                if (checkValid && date.length == 4) {
                    val calendar: Calendar = Calendar.getInstance()
                    val year = calendar.get(Calendar.YEAR).toString()
                    val currentMonth = calendar.get(Calendar.MONTH).toString().toInt() + 1
                    val inputMonth = date.substring(0, 2).toInt()
                    val inputYY = date.substring(2, 4).toInt()
                    val currentYY = year.substring(2, 4).toInt()
                    checkValid = if (inputMonth > 12 || inputMonth == 0) false
                    else if (inputYY < currentYY) false
                    else if (inputYY == currentYY && inputMonth < currentMonth) false
                    else !(inputYY > currentYY && inputYY > currentYY + 5)
                }
                if (checkValid) {
                    cardExpiryValid = date
                    if (!cardNumberIsValid) {
                        etCardNumber.requestFocus()
                    } else activity?.hideSoftInput()
                }

                cardExpiryIsValid = checkValid
                tvErrorMsgExpiry.isVisible = !checkValid

                checkValidForm()
                if (etCardExpiry.text.toString().isEmpty()) {
                    tvErrorMsgExpiry.isVisible = false
                }
            })
        }
    }

    private fun checkValidForm() {
        bn.apply {
            val isAllFormsValid = if (amountValid != null && amountValid!! >= CONSTANTS.PAY_MIN_AMOUNT && amountValid!! <= CONSTANTS.PAY_MAX_AMOUNT)
                amountIsValid && this@ReplenishBalanceFragment.phoneNumber.length == 12
            else false

            val cardValid = if (payWithAnotherCard) cardNumberIsValid && cardExpiryIsValid else selectedCard != null

            btnPay.isEnabled = isAllFormsValid && cardValid
        }
    }

    private fun getNewVendorId(type: Int): Tuple3 {
        return when (type) {
            99 -> Tuple3("100240", "Uzmobile GSM", getResources(type))
            95 -> Tuple3("100243", "Uzmobile CDMA", getResources(type))
            98 -> Tuple3("100083", "Perfectum", getResources(type))
            97 -> Tuple3("100082", "UMS", getResources(type))
            88 -> Tuple3("100082", "UMS", getResources(type))
            94 -> Tuple3("100081", "Ucell", getResources(type))
            93 -> Tuple3("100081", "Ucell", getResources(type))
            91 -> Tuple3("100080", "Beeline", getResources(type))
            90 -> Tuple3("100080", "Beeline", getResources(type))
            71 -> Tuple3("100406", "TShTT Абонентская плата", getResources(type))
            else -> Tuple3("-100001", "Unknown", getResources(type))
        }
    }

    private fun getResources(prefix: Int): Int {
        return when (prefix) {
            99 -> R.drawable.agr_logo_uztelekom
            95 -> R.drawable.agr_logo_uztelekom
            98 -> R.drawable.agr_log_perfectum
            97 -> R.drawable.agr_logo_ums
            88 -> R.drawable.agr_logo_ums
            94 -> R.drawable.agr_logo_ucell
            93 -> R.drawable.agr_logo_ucell
            91 -> R.drawable.agr_logo_beeline
            90 -> R.drawable.agr_logo_beeline
            71 -> R.drawable.agr_logo_uztelekom
            else -> 0
        }
    }

    override fun onDestroy() {
        _bn = null
        super.onDestroy()
    }
}