package com.gh.common.dialog

import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.InputFilter
import android.view.LayoutInflater
import androidx.core.widget.addTextChangedListener
import com.gh.gamecenter.R
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogReserveReminderPhoneNumberBinding
import com.gh.gamecenter.entity.ReserveModifyEntity
import com.gh.gamecenter.entity.ValidateCodeResponse
import com.halo.assistant.fragment.reserve.OnReserveReminderListener
import com.halo.assistant.fragment.reserve.ReserveReminderRepository
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
import java.util.concurrent.TimeUnit


class ReserveReminderPhoneNumberDialog(
    context: Context,
    themeResId: Int,
    private val dialogType: Int,
    private val phoneNumber: String,
    private var serviceId: String,
    private val gameId: String,
    private val repository: ReserveReminderRepository,
    private val listener: OnReserveReminderListener
) :
    Dialog(context, themeResId) {

    private val compositeDisposable = CompositeDisposable()

    private lateinit var binding: DialogReserveReminderPhoneNumberBinding

    private var hasValidated = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DialogReserveReminderPhoneNumberBinding.inflate(LayoutInflater.from(context))
        setContentView(binding.root)
        initView()
    }

    private fun initView() {
        binding.vClose.setOnClickListener {
            dismiss()
        }

        setSubmitState(phoneNumber)
        binding.etInput.addTextChangedListener {
            val content = binding.etInput.text?.toString() ?: ""
            if (dialogType == DIALOG_TYPE_BIND_PHONE || dialogType == DIALOG_TYPE_CHANGE_PHONE) {
                setSubmitState(content)
            } else {
                val length = content.length
                if (length == VALIDATE_CODE_LENGTH) {
                    verifyPhoneNumber(content)
                }
            }

        }

        when (dialogType) {
            DIALOG_TYPE_BIND_PHONE -> {
                binding.tvTitle.setText(R.string.enable_sms_reminder)
                binding.tvDescription.setText(R.string.enable_sms_reminder_description)
                binding.etInput.setText(phoneNumber)
                binding.etInput.setHint(com.gh.gamecenter.login.R.string.input_phone_hint)
            }

            DIALOG_TYPE_CHANGE_PHONE -> {
                binding.tvTitle.setText(R.string.change_phone_number_2)
                binding.tvDescription.setText(R.string.enable_sms_reminder_description)
                binding.etInput.setText(phoneNumber)
                binding.etInput.setHint(com.gh.gamecenter.login.R.string.input_phone_hint)
            }

            DIALOG_TYPE_VERIFY_PHONE -> {
                startCountDown()
                binding.tvTitle.setText(R.string.please_input_sms_verify_code)
                if (phoneNumber.length == PHONE_NUMBER_LENGTH) {
                    val phoneNumberWithMask = phoneNumber.substring(0, 3) + MASK + phoneNumber.substring(7)
                    binding.tvDescription.text =
                        context.getString(R.string.verify_code_send_with_phone_number, phoneNumberWithMask)
                }
                binding.tvSubmit.alpha = 1.0F
                binding.etInput.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(VALIDATE_CODE_LENGTH))
                binding.etInput.setHint(R.string.please_input_verify_code)

            }
        }
        binding.tvSubmit.setOnClickListener {
            val text = binding.etInput.text?.toString() ?: ""
            if (dialogType == DIALOG_TYPE_VERIFY_PHONE) {
                resendValidateCode()
            } else {
                if (isEnableSubmit(text)) {
                    when (dialogType) {
                        DIALOG_TYPE_BIND_PHONE -> bindPhoneNumber(text)
                        DIALOG_TYPE_CHANGE_PHONE -> bindPhoneNumber(text)
                    }
                } else {
                    if (text != phoneNumber) {
                        ToastUtils.toast(R.string.invalid_phone_number_format.toResString())
                    }
                }

            }

        }
    }


    private fun resendValidateCode() {
        repository.sendVerifyCode(phoneNumber)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ValidateCodeResponse>() {
                override fun onSuccess(data: ValidateCodeResponse) {
                    serviceId = data.serviceId
                    startCountDown()
                }

            }).let(compositeDisposable::add)
    }

    private fun verifyPhoneNumber(content: String) {
        repository.verifyPhoneNumber(phoneNumber, content, serviceId)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    hasValidated = true
                    listener.phoneNumberValidateSuccessfully()
                    ToastUtils.toast(R.string.phone_number_validate_successfully.toResString())
                    dismiss()

                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    binding.etInput.text = null
                    ToastUtils.toast(R.string.phone_number_validate_failure.toResString())
                }
            }).let(compositeDisposable::add)
    }


    private fun bindPhoneNumber(phone: String) {
        repository.bindPhone(gameId, phone)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ReserveModifyEntity>() {
                override fun onSuccess(data: ReserveModifyEntity) {
                    listener.bindPhoneSuccessfully(data.smsConfig.mobileValidated, phone)
                    dismiss()
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    if (exception is HttpException) {
                        try {
                            val string = exception.response().errorBody()?.string()
                            if (!string.isNullOrBlank()) {
                                val json = JSONObject(string)
                                val message = json.getJSONObject("toast").getString("sms_config.mobile")
                                ToastUtils.showToast(message)
                            }
                        } catch (e: Exception) {
                            // no implement
                        }
                    }

                }
            }).let(compositeDisposable::add)
    }


    private fun startCountDown() {
        binding.tvSubmit.isEnabled = false
        binding.tvSubmit.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_light_fill_gray)
        binding.tvSubmit.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
        Observable.interval(0, 1, TimeUnit.SECONDS)
            .take(COUNT_DOWN_DURATION)
            .map {
                COUNT_DOWN_DURATION - it
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<Long>() {
                override fun onSubscribe(d: Disposable) {
                    compositeDisposable.add(d)
                }


                override fun onNext(time: Long) {
                    binding.tvSubmit.text = context.getString(R.string.resend_with_time, "$time")
                }

                override fun onComplete() {
                    binding.tvSubmit.isEnabled = true
                    binding.tvSubmit.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_fill_blue)
                    binding.tvSubmit.setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
                    binding.tvSubmit.setText(R.string.resend)

                }
            })
    }

    override fun dismiss() {
        compositeDisposable.clear()
        if (dialogType == DIALOG_TYPE_VERIFY_PHONE && !hasValidated) {
            ToastUtils.toast(R.string.phone_number_validate_cancel.toResString())
        }
        super.dismiss()
    }

    private fun isEnableSubmit(phone: String) =
        PHONE_NUMBER_PATTERN.toRegex().matches(phone)
                && if (dialogType == DIALOG_TYPE_CHANGE_PHONE) phone != phoneNumber else true

    private fun setSubmitState(phone: String) {
        val isEnable = isEnableSubmit(phone)
        binding.tvSubmit.alpha = if (isEnable) {
            TV_SUBMIT_ENABLE_ALPHA
        } else {
            TV_SUBMIT_UNABLE_ALPHA
        }
    }

    companion object {

        private const val PHONE_NUMBER_PATTERN = "^1\\d{10}$"
        private const val MASK = "****"
        private const val PHONE_NUMBER_LENGTH = 11
        private const val VALIDATE_CODE_LENGTH = 6

        const val DIALOG_TYPE_BIND_PHONE = 0
        const val DIALOG_TYPE_CHANGE_PHONE = 1
        const val DIALOG_TYPE_VERIFY_PHONE = 2

        private const val COUNT_DOWN_DURATION = 60L

        private const val TV_SUBMIT_ENABLE_ALPHA = 1F
        private const val TV_SUBMIT_UNABLE_ALPHA = 0.4F

        fun create(
            context: Context,
            dialogType: Int,
            phoneNumber: String,
            serviceId: String,
            gameId: String,
            repository: ReserveReminderRepository,
            listener: OnReserveReminderListener
        ) =
            ReserveReminderPhoneNumberDialog(
                context,
                com.gh.gamecenter.common.R.style.DialogWindowTransparent,
                dialogType,
                phoneNumber,
                serviceId,
                gameId,
                repository,
                listener
            )
    }
}