package kr.co.vividnext.sodalive.user.signup

import android.net.Uri
import androidx.core.util.PatternsCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.user.Gender
import kr.co.vividnext.sodalive.user.UserRepository
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File

class SignUpViewModel(private val repository: UserRepository) : BaseViewModel() {
    enum class EmailSignUpStep {
        @SerializedName("STEP_1") STEP_1,
        @SerializedName("STEP_2") STEP_2
    }

    var email = ""
    var password = ""
    var passwordRe = ""
    var nickname = ""
    var profileImageUri: Uri? = null

    private val _genderLiveData = MutableLiveData(Gender.NONE)
    val genderLiveData: LiveData<Gender>
        get() = _genderLiveData

    private val _isAgreeTermsOfServiceLiveData = MutableLiveData(false)
    val isAgreeTermsOfServiceLiveData: LiveData<Boolean>
        get() = _isAgreeTermsOfServiceLiveData

    private val _isAgreePrivacyPolicyLiveData = MutableLiveData(false)
    val isAgreePrivacyPolicyLiveData: LiveData<Boolean>
        get() = _isAgreePrivacyPolicyLiveData

    private val _signUpErrorLiveData = MutableLiveData<SignUpError>()
    val signUpErrorLiveData: LiveData<SignUpError>
        get() = _signUpErrorLiveData

    private val _toastLiveData = MutableLiveData<String?>()
    val toastLiveData: LiveData<String?>
        get() = _toastLiveData

    private var _isLoading = MutableLiveData(false)
    val isLoading: LiveData<Boolean>
        get() = _isLoading

    private val _stepLiveData = MutableLiveData(EmailSignUpStep.STEP_1)
    val stepLiveData: LiveData<EmailSignUpStep>
        get() = _stepLiveData

    lateinit var getRealPathFromURI: (Uri) -> String?

    fun setStep(step: EmailSignUpStep = EmailSignUpStep.STEP_2) {
        _stepLiveData.postValue(step)
    }

    fun signUp(onSuccess: (String?) -> Unit) {
        if (stepLiveData.value!! == EmailSignUpStep.STEP_1) {
            if (validationStep1()) return

            setStep()
            return
        }

        if (validationStep2()) return

        val request = SignUpRequest(
            email = email,
            password = password,
            nickname = nickname,
            gender = _genderLiveData.value!!,
            isAgreeTermsOfService = _isAgreeTermsOfServiceLiveData.value!!,
            isAgreePrivacyPolicy = _isAgreePrivacyPolicyLiveData.value!!
        )

        val requestJson = Gson().toJson(request)

        val profileImage = if (profileImageUri != null) {
            val file = File(getRealPathFromURI(profileImageUri!!))
            MultipartBody.Part.createFormData(
                "profileImage",
                file.name,
                file.asRequestBody("image/*".toMediaType())
            )
        } else {
            null
        }

        _isLoading.value = true
        compositeDisposable.add(
            repository.signUp(
                profileImage,
                requestJson.toRequestBody("text/plain".toMediaType())
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success && it.data != null) {
                            SharedPreferenceManager.token = it.data.token
                            SharedPreferenceManager.email = it.data.email
                            SharedPreferenceManager.userId = it.data.userId
                            SharedPreferenceManager.nickname = it.data.nickname
                            SharedPreferenceManager.profileImage = it.data.profileImage
                            _isLoading.value = false
                            onSuccess(it.message)
                        } else {
                            _isLoading.value = false
                            if (it.errorProperty != null && it.message != null) {
                                _signUpErrorLiveData.postValue(
                                    SignUpError(it.errorProperty, it.message)
                                )
                            } else if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                            }
                        }
                    },
                    {
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    private fun validationStep1(): Boolean {
        if (email.isBlank()) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "email",
                    "이메일을 입력하세요."
                )
            )

            return true
        }

        if (password.isBlank()) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "password",
                    "비밀번호를 입력하세요."
                )
            )

            return true
        }

        if (password != passwordRe) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "password",
                    "비밀번호가 일치하지 않습니다."
                )
            )

            return true
        }

        if (
            !_isAgreePrivacyPolicyLiveData.value!! ||
            !_isAgreeTermsOfServiceLiveData.value!!
        ) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "",
                    "약관에 동의하셔야 회원가입이 가능합니다."
                )
            )

            return true
        }

        if (!PatternsCompat.EMAIL_ADDRESS.matcher(email).matches()) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "email",
                    "올바른 이메일을 입력해 주세요"
                )
            )

            return true
        }

        if (
            "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d$@!%*#?&]{8,}$"
                .toRegex()
                .matches(password)
                .not()
        ) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "password",
                    "영문, 숫자 포함 8자 이상의 비밀번호를 입력해 주세요."
                )
            )
        }

        return false
    }

    private fun validationStep2(): Boolean {
        if (nickname.isBlank() || nickname.length < 2) {
            _signUpErrorLiveData.postValue(
                SignUpError(
                    "nickname",
                    "닉네임은 2자 이상 입력해 주세요."
                )
            )

            return true
        }

        return false
    }

    fun onClickCheckboxTermsOfService() {
        _isAgreeTermsOfServiceLiveData.postValue(!_isAgreeTermsOfServiceLiveData.value!!)
    }

    fun onClickCheckboxPrivacyPolicy() {
        _isAgreePrivacyPolicyLiveData.postValue(!_isAgreePrivacyPolicyLiveData.value!!)
    }

    fun changeGender(gender: Gender) {
        _genderLiveData.postValue(gender)
    }
}
