package kr.co.vividnext.sodalive.audio_content.upload

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.audio_content.upload.theme.GetAudioContentThemeResponse
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 AudioContentUploadViewModel(
    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(true)
    val isAvailableCommentLiveData: LiveData<Boolean>
        get() = _isAvailableCommentLiveData

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

    lateinit var getRealPathFromURI: (Uri) -> String?

    var title = ""
    var detail = ""
    var tags = ""
    var price = 0
    var theme: GetAudioContentThemeResponse? = null
    var coverImageUri: Uri? = null
    var contentUri: Uri? = null

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

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

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

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

            val request = CreateAudioContentRequest(
                title = title,
                detail = detail,
                tags = tags,
                price = price,
                themeId = theme!!.id,
                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
            }

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

                        override fun writeTo(sink: BufferedSink) {
                            file.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 file.length()
                        }
                    }
                )
            } else {
                null
            }

            if (coverImage == null) {
                _toastLiveData.postValue("커버이미지를 선택해 주세요.")
                return
            }

            if (contentFile == null) {
                _toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
                return
            }

            compositeDisposable.add(
                repository.uploadAudioContent(
                    coverImage = coverImage,
                    contentFile = contentFile,
                    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 (title.isBlank()) {
            _toastLiveData.postValue("제목을 입력해 주세요.")
            return false
        }

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

        if (theme == null) {
            _toastLiveData.postValue("테마를 선택해 주세요.")
            return false
        }

        if (coverImageUri == null) {
            _toastLiveData.postValue("커버이미지를 선택해 주세요.")
            return false
        }

        if (contentUri == null) {
            _toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
            return false
        }

        if (!isPriceFreeLiveData.value!! && price < 10) {
            _toastLiveData.postValue("콘텐츠의 최소금액은 10캔 입니다.")
            return false
        }

        return true
    }
}
