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 dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import timber.log.Timber
import uz.agr.mobiuz.ui.fast_action.animation.getColorCompat
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.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.home.HomeViewModel
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: HomeViewModel 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 {
            addCard.isVisible = list.isEmpty()
            selectCardView.isVisible = list.isNotEmpty()
            if (list.isNotEmpty()) {
                selectCardView.showCard(list[0], 0)
            }
        }
    }

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

            override fun server(serverData: List<CardInfo>) {
                Timber.e("server: ${serverData.size}")
                setCardListAdapter(serverData)
            }
        })
    }

    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 code == "97" || code == "88"
    }

    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) {}

                override fun success(data: Boolean) {
                    if (payWithAnotherCard) payWithAnotherCard(cardNumberValid, cardExpiryValid, btnSwitch.isChecked, phoneNumber, vendorFormParams)
                    else vendorPay(selectedCard, phoneNumber, 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) {
                    // todo Shohboz aka uchun
                    navController.navigate(
                        R.id.verificationFragment,
                        bundleOf(
                            CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ANOTHER_CARD,
                            CONSTANTS.PHONE to "998" + bn.etPhone.unmaskedText,
                            CONSTANTS.PAY_AMOUNT to amountValid,
                            CONSTANTS.TRANSACTION_ID to transactionId
                        )
                    )
                }

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

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

                override fun showSuccessfulPayment(transactionId: Long) {
                    // todo must add to local database
                    viewModel
                    navController.navigate(
                        R.id.paymentSuccessfulFragment,
                        bundleOf(
                            CONSTANTS.PHONE to phoneNumber,
                            CONSTANTS.PAY_AMOUNT to amountValid
                        )
                    )
                }
            })
        }
    }

    private fun deleteCard(cardNumber: String, cardExpiry: String) {
        MobiUz.getLocalCards(object : BaseListener<List<CardInfo>> {
            override fun error(message: String) {}
            override fun loading(boolean: Boolean) {}
            override fun success(data: List<CardInfo>) {
                val card: CardInfo? = data.find {
                    it.expiry.filter { it.isDigit() } == cardExpiry.filter { it.isDigit() }
                            && it.pan.replace(" ", "").substring(0, 6) == cardNumber.replace(" ", "").substring(0, 6)
                            && it.pan.replace(" ", "").substring(it.pan.length - 4, it.pan.length) ==
                            cardNumber.replace(" ", "").substring(cardNumber.length - 4, cardNumber.length)
                }
                if (card != null) {
                    MobiUz.deleteCard(card, object : BaseListener<Boolean> {
                        override fun error(message: String) {}
                        override fun loading(boolean: Boolean) {}
                        override fun success(data: Boolean) {}
                    })
                }
            }
        })
    }

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

                navController.navigate(
                    R.id.verificationFragment,
                    bundleOf(
                        CONSTANTS.TYPE_VERIFICATION to CONSTANTS.TYPE_ANOTHER_CARD,
                        CONSTANTS.TRANSACTION_ID to transactionId,
                        CONSTANTS.PHONE to "998" + bn.etPhone.unmaskedText,
                        CONSTANTS.SAVED_CARD to isSave,
                        CONSTANTS.PAY_AMOUNT to amountValid,
                        CONSTANTS.PAY_CARD_NUMBER to cardNumber
                    )
                )
                // todo Shohboz aka uchun
            }

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

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

            override fun showSuccessfulPayment(transactionId: Long) {
                navController.navigate(
                    R.id.paymentSuccessfulFragment,
                    bundleOf(
                        CONSTANTS.PHONE to "998" + bn.etPhone.unmaskedText,
                        CONSTANTS.PAY_AMOUNT to amountValid,
                        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 = false
                    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()
    }
}