package kr.co.vividnext.sodalive.explorer.profile.creator_community.write

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 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 CreatorCommunityWriteViewModel(
    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 _isAdultLiveData = MutableLiveData(false)
    val isAdultLiveData: LiveData<Boolean>
        get() = _isAdultLiveData

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

    private val _isPriceFreeLiveData = MutableLiveData(true)
    val isPriceFreeLiveData: LiveData<Boolean>
        get() = _isPriceFreeLiveData

    private val _isShowPriceUiLiveData = MutableLiveData(false)
    val isShowPriceUiLiveData: LiveData<Boolean>
        get() = _isShowPriceUiLiveData

    lateinit var getRealPathFromURI: (Uri) -> String?

    var price = 0
    var content = ""
    var audioFile: File? = null
    private var imageUri: Uri? = null

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

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

    fun setPriceFree(isPriceFree: Boolean) {
        _isPriceFreeLiveData.postValue(isPriceFree)
    }

    fun setImageUri(uri: Uri) {
        this.imageUri = uri
        _isShowPriceUiLiveData.postValue(true)
    }

    fun createCommunityPost(onSuccess: () -> Unit) {
        if (!_isLoading.value!! && validateData()) {
            _isLoading.postValue(true)

            val request = CreateCommunityPostRequest(
                content = content,
                price = price,
                isAdult = _isAdultLiveData.value!!,
                isCommentAvailable = _isAvailableCommentLiveData.value!!
            )

            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
            }

            val multipartAudioFile = if (audioFile != null) {
                MultipartBody.Part.createFormData(
                    "audioFile",
                    audioFile!!.name,
                    body = object : RequestBody() {
                        override fun contentType(): MediaType {
                            return "audio/*".toMediaType()
                        }

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

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

            compositeDisposable.add(
                repository.createCommunityPost(
                    audioFile = multipartAudioFile,
                    postImage = postImage,
                    request = requestJson.toRequestBody("text/plain".toMediaType()),
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            if (it.success && it.data != null) {
                                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 (content.isBlank() || content.length < 5) {
            _toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
            return false
        }

        try {
            if (!isPriceFreeLiveData.value!!) {
                if (price < 5) {
                    _toastLiveData.postValue("최소금액은 5캔 입니다.")
                    return false
                }

                if (imageUri == null) {
                    _toastLiveData.postValue("유료 게시글 등록을 위해서는 이미지가 필요합니다.")
                    return false
                }
            }
        } catch (e: Exception) {
            _toastLiveData.postValue("가격은 숫자만 입력 가능 합니다.")
            return false
        }

        return true
    }
}
