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.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 timber.log.Timber
import uz.agr.mobiuz.ui.fast_action.animation.getColorCompat
import uz.agr.mobiuz.ui.replenish.dialog.SelectCardBottomDialogFragment
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.TextWatcherWrapper
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.pgw_core.VendorPayConfirm
import uz.agr.sdk.pgw_core.mobi.BaseListener
import uz.agr.sdk.pgw_core.mobi.CardListenerMobi
import uz.agr.sdk.pgw_core.mobi.MobiUz
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.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 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 = ""

    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(uz.agr.mobiuz.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.PRIVACY_POLICY_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() {

    }

    private fun setCardListAdapter(list: List<CardInfo>) {
        bn.apply {
            initSelectCardView(list)
            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() {
        Timber.d("getAllCards")
        MobiUz.getAllCards(object : CardListenerMobi<CardInfo> {
            override fun error(message: String) {
                Timber.e("error: $message")
            }

            override fun loading(boolean: Boolean) {
                Timber.e("progress: $boolean")
                showProgressDialog(boolean)
            }

            override fun local(localData: List<CardInfo>) {
                Timber.e("local: ${localData.size}")
                setCardListAdapter(localData)
                if (localData.isNotEmpty()) {
                    showSelectedCard(localData.first(), 0)
                }
            }

            override fun server(serverData: List<CardInfo>) {
                Timber.e("server: ${serverData.size}")
                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(uz.agr.mobiuz.R.string.agr_mobi_uz_not_enough_money))
                }
            }
        }
    }

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

    private fun pay() {
        bn.apply {
            val phoneNumber = "998${etPhone.unmaskedText}"
            val amount = amountValid ?: 0
            if (!isMobiUz(phoneNumber.substring(3, 5))) {
                showSnackMessage(getString(uz.agr.mobiuz.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
            }

            MobiUz.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, /*pref.userPhone.filter { it.isDigit() }*/"998917797278",
                        vendorFormParams
                    )
                    else vendorPay(selectedCard, /*pref.userPhone.filter { it.isDigit() }*/"998917797278", vendorFormParams)
                }
            })
        }
    }

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

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

                    val monitoring = Monitoring(
                        date = System.currentTimeMillis(),
                        phone = "998${bn.etPhone.unmaskedText}",
                        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 = "998${etPhone.unmaskedText}",
                        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>) {

        MobiUz.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("+", "")
                if (responsePhone.substring(0, 5) == inputPhone.substring(0, 5) &&
                    responsePhone.substring(responsePhone.length - 2, responsePhone.length) == inputPhone.substring(inputPhone.length - 2, inputPhone.length)
                ) isSave = true else {
//                    deleteCard(cardNumber, cardExpiry)
                }


                val monitoring = Monitoring(
                    date = System.currentTimeMillis(),
                    phone = "998${bn.etPhone.unmaskedText}",
                    amount = etAmount.text.toString().filter { it.isDigit() }.toLong(),
                    pan = cardNumber
                )

                navController.navigate(
                    R.id.verificationFragment,
                    bundleOf(
                        CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ANOTHER_CARD,
                        CONSTANTS.TRANSACTION_ID to transactionId,
                        CONSTANTS.PHONE to monitoring.phone,
                        CONSTANTS.PAY_AMOUNT to monitoring.amount,
                        CONSTANTS.SAVED_CARD to if (isSave) CONSTANTS.IS_SAVED_CARD else CONSTANTS.IS_NOT_SAVED_CARD,
                        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 = "998${etPhone.unmaskedText}",
                    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 saveCard,
                        CONSTANTS.PAY_CARD_NUMBER to cardNumber
                    )
                )
            }
        })
    }

    private fun onCLickAddCard() {
        requireActivity().hideSoftInput()
        val dialog = SelectAnotherCard()
        dialog.setListener(object : SelectAnotherCard.Listener {
            override fun onClickAnotherCard() {
                bn.apply {
                    selectedCard = null
                    payWithAnotherCard = true
                    selectCardView.showNewCard()
                    selectCardView.isVisible = true
                    addCardForm.isVisible = payWithAnotherCard
                    addCard.isVisible = false
                    checkValidForm()
                }
                dialog.dismiss()
            }

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

    private fun initPhone() {
        bn.apply {
            etPhone.addTextChangedListener(object : TextWatcherWrapper() {
                override fun afterTextChanged(s: Editable) {
                    val isAllFormsValid = if (amountValid != null && amountValid!! >= CONSTANTS.PAY_MIN_AMOUNT && amountValid!! <= CONSTANTS.PAY_MAX_AMOUNT)
                        amountIsValid && s.toString().filter { it.isDigit() }.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

                    etCardNumber.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_unchecked)
                    etCardNumber.setTextColor(getColorCompat(uz.agr.mobiuz.R.color.agr_text_color))
                } else {
                    etCardNumber.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_error)
                    etCardNumber.setTextColor(getColorCompat(uz.agr.mobiuz.R.color.primary100))
                }
                tvErrorMsg.isVisible = !valid

                checkValidForm()
            })
        }
    }

    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()

                    etCardExpiry.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_unchecked)
                    etCardExpiry.setTextColor(getColorCompat(uz.agr.mobiuz.R.color.agr_text_color))
                } else {
                    etCardExpiry.setBackgroundResource(uz.agr.mobiuz.R.drawable.agr_edit_text_error)
                    etCardExpiry.setTextColor(getColorCompat(uz.agr.mobiuz.R.color.primary100))
                }

                cardExpiryIsValid = checkValid
                tvErrorMsgExpiry.isVisible = !checkValid

                checkValidForm()
            })
        }
    }

    private fun checkValidForm() {
        bn.apply {
            val isAllFormsValid = if (amountValid != null && amountValid!! >= CONSTANTS.PAY_MIN_AMOUNT && amountValid!! <= CONSTANTS.PAY_MAX_AMOUNT)
                amountIsValid && etPhone.unmaskedText.toString().length == 9
            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 -> uz.agr.mobiuz.R.drawable.agr_logo_uztelekom
            95 -> uz.agr.mobiuz.R.drawable.agr_logo_uztelekom
            98 -> uz.agr.mobiuz.R.drawable.agr_log_perfectum
            97 -> uz.agr.mobiuz.R.drawable.agr_logo_ums
            88 -> uz.agr.mobiuz.R.drawable.agr_logo_ums
            94 -> uz.agr.mobiuz.R.drawable.agr_logo_ucell
            93 -> uz.agr.mobiuz.R.drawable.agr_logo_ucell
            91 -> uz.agr.mobiuz.R.drawable.agr_logo_beeline
            90 -> uz.agr.mobiuz.R.drawable.agr_logo_beeline
            71 -> uz.agr.mobiuz.R.drawable.agr_logo_uztelekom
            else -> 0
        }
    }

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