package kr.co.vividnext.sodalive.explorer.profile.creator_community.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.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
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 CreatorCommunityModifyViewModel(
    private val repository: CreatorCommunityRepository
) : 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 _imageUrlLiveData = MutableLiveData<String?>()
    val imageUrlLiveData: LiveData<String?>
        get() = _imageUrlLiveData

    private val _contentLiveData = MutableLiveData("")
    val contentLiveData: LiveData<String>
        get() = _contentLiveData

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

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

    lateinit var getRealPathFromURI: (Uri) -> String?

    var postId = 0L
    var content = ""
    var imageUri: Uri? = null
    private var communityPost: GetCommunityPostListResponse? = null

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

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

    fun getCommunityPostDetail(onFailure: (() -> Unit)? = null) {
        communityPost = null
        _isLoading.value = true

        compositeDisposable.add(
            repository.getCommunityPostDetail(
                postId = postId,
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        _isLoading.value = false

                        if (it.success && it.data != null) {
                            communityPost = it.data
                            _imageUrlLiveData.value = it.data.imageUrl
                            _contentLiveData.value = it.data.content
                            _isAdultLiveData.value = it.data.isAdult
                            _isAvailableCommentLiveData.value = it.data.isCommentAvailable
                        } else {
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                )
                            }

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

    fun modifyCommunityPost(onSuccess: () -> Unit) {
        if (!_isLoading.value!! && validateData()) {
            _isLoading.value = true
            val request = ModifyCommunityPostRequest(
                creatorCommunityId = postId,
                content = if (communityPost!!.content != content) {
                    content
                } else {
                    null
                },
                isCommentAvailable = if (
                    communityPost!!.isCommentAvailable != _isAvailableCommentLiveData.value!!
                ) {
                    _isAvailableCommentLiveData.value!!
                } else {
                    null
                },
                isAdult = if (communityPost!!.isAdult != _isAdultLiveData.value!!) {
                    _isAdultLiveData.value!!
                } else {
                    null
                }
            )

            val requestJson = Gson().toJson(request)

            val postImage = if (imageUri != null) {
                val file = File(getRealPathFromURI(imageUri!!))
                MultipartBody.Part.createFormData(
                    "postImage",
                    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.modifyCommunityPost(
                    postImage,
                    request = requestJson.toRequestBody("text/plain".toMediaType()),
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            _isLoading.value = false
                            if (it.success) {
                                onSuccess()
                            } else {
                                if (it.message != null) {
                                    _toastLiveData.postValue(it.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }
                        },
                        {
                            _isLoading.value = false
                            it.message?.let { message -> Logger.e(message) }
                            _toastLiveData.postValue(
                                "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                            )
                        }
                    )
            )
        }
    }

    private fun validateData(): Boolean {
        if (content.isBlank() || content.length < 5) {
            _toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
            return false
        }

        return true
    }
}
