package kr.co.vividnext.sodalive.audio_content.modify

import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okio.BufferedSink
import java.io.File

class AudioContentModifyViewModel(
    private val repository: AudioContentRepository
) : BaseViewModel() {

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

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

    private val _isAdultLiveData = MutableLiveData(false)
    val isAdultLiveData: LiveData<Boolean>
        get() = _isAdultLiveData

    private val _isAvailableCommentLiveData = MutableLiveData(false)
    val isAvailableCommentLiveData: LiveData<Boolean>
        get() = _isAvailableCommentLiveData

    private val _titleLiveData = MutableLiveData("")
    val titleLiveData: LiveData<String>
        get() = _titleLiveData

    private val _detailLiveData = MutableLiveData("")
    val detailLiveData: LiveData<String>
        get() = _detailLiveData

    private val _coverImageLiveData = MutableLiveData("")
    val coverImageLiveData: LiveData<String>
        get() = _coverImageLiveData

    private val _isAdultShowUiLiveData = MutableLiveData(true)
    val isAdultShowUiLiveData: LiveData<Boolean>
        get() = _isAdultShowUiLiveData

    lateinit var getRealPathFromURI: (Uri) -> String?

    var contentId: Long = 0
    var title: String? = null
    var detail: String? = null
    var coverImageUri: Uri? = null

    fun setAdult(isAdult: Boolean) {
        _isAdultLiveData.postValue(isAdult)
    }

    fun setAvailableComment(isAvailableComment: Boolean) {
        _isAvailableCommentLiveData.postValue(isAvailableComment)
    }

    fun getAudioContentDetail(audioContentId: Long, onFailure: (() -> Unit)? = null) {
        this.contentId = audioContentId
        _isLoading.value = true

        compositeDisposable.add(
            repository.getAudioContentDetail(
                audioContentId = audioContentId,
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success && it.data != null) {
                            _titleLiveData.value = it.data.title
                            _detailLiveData.value = it.data.detail
                            _coverImageLiveData.value = it.data.coverImageUrl
                            _isAvailableCommentLiveData.value = it.data.isCommentAvailable
                            _isAdultLiveData.value = it.data.isAdult
                            _isAdultShowUiLiveData.value = !it.data.isAdult
                        } else {
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                )
                            }

                            if (onFailure != null) {
                                onFailure()
                            }
                        }

                        _isLoading.value = false
                    },
                    {
                        _isLoading.value = false
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                        if (onFailure != null) {
                            onFailure()
                        }
                    }
                )
        )
    }

    fun modifyAudioContent(onSuccess: () -> Unit) {
        if (!_isLoading.value!! && contentId > 0 && validateData()) {
            _isLoading.value = true

            val request = ModifyAudioContentRequest(
                contentId = contentId,
                title = title,
                detail = detail,
                isAdult = _isAdultLiveData.value!!,
                isCommentAvailable = _isAvailableCommentLiveData.value!!
            )

            val requestJson = Gson().toJson(request)

            val coverImage = if (coverImageUri != null) {
                val file = File(getRealPathFromURI(coverImageUri!!))
                MultipartBody.Part.createFormData(
                    "coverImage",
                    file.name,
                    body = object : RequestBody() {
                        override fun contentType(): MediaType {
                            return "image/*".toMediaType()
                        }

                        override fun writeTo(sink: BufferedSink) {
                            file.inputStream().use { inputStream ->
                                val buffer = ByteArray(1024)
                                var bytesRead: Int
                                while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                                    sink.write(buffer, 0, bytesRead)
                                }
                            }
                        }

                        override fun contentLength(): Long {
                            return file.length()
                        }
                    }
                )
            } else {
                null
            }

            compositeDisposable.add(
                repository.modifyAudioContent(
                    coverImage = coverImage,
                    request = requestJson.toRequestBody("text/plain".toMediaType()),
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            if (it.success) {
                                _toastLiveData.postValue("수정되었습니다.")
                                onSuccess()
                            } else {
                                if (it.message != null) {
                                    _toastLiveData.postValue(it.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }
                            _isLoading.postValue(false)
                        },
                        {
                            _isLoading.postValue(false)
                            it.message?.let { message -> Logger.e(message) }
                            _toastLiveData.postValue(
                                "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                            )
                        }
                    )
            )
        }
    }

    private fun validateData(): Boolean {
        if (title != null && title!!.isBlank()) {
            _toastLiveData.postValue("제목을 입력해 주세요.")
            return false
        }

        if (detail != null && (detail!!.isBlank() || detail!!.length < 5)) {
            _toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
            return false
        }

        return true
    }
}
