package kr.co.vividnext.sodalive.live.roulette.config

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
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.live.roulette.RouletteItem
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
import kotlin.math.floor

class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {

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

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

    private val _optionsLiveData = MutableLiveData<List<RouletteOption>>(listOf())
    val optionsLiveData: LiveData<List<RouletteOption>>
        get() = _optionsLiveData

    private val _isActiveLiveData = MutableLiveData(false)
    val isActiveLiveData: LiveData<Boolean>
        get() = _isActiveLiveData

    private val _canLiveData = MutableLiveData(0)
    val canLiveData: LiveData<Int>
        get() = _canLiveData

    private val _roulettePreviewLiveData = MutableLiveData<RoulettePreview>()
    val roulettePreviewLiveData: LiveData<RoulettePreview>
        get() = _roulettePreviewLiveData

    private val options = mutableListOf<RouletteOption>()
    var can = 0
    var isActive = false

    fun plusWeight(optionIndex: Int) {
        val currentOption = options[optionIndex]
        options[optionIndex] = currentOption.copy(weight = currentOption.weight + 1)
        recalculatePercentages(options)
    }

    fun subtractWeight(optionIndex: Int) {
        if (options[optionIndex].weight > 1) {
            val currentOption = options[optionIndex]
            options[optionIndex] = currentOption.copy(weight = currentOption.weight - 1)
            recalculatePercentages(options)
        }
    }

    fun addOption(newOption: RouletteOption) {
        if (options.size >= 10) return

        options.add(newOption)
        recalculatePercentages(options)
    }

    fun deleteOption(index: Int) {
        val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
        removeAllAndAddOptions(updatedOptions)
        recalculatePercentages(updatedOptions)
    }

    fun inputOption(optionIndex: Int, title: String) {
        val currentOption = options[optionIndex]
        options[optionIndex] = currentOption.copy(title = title)
    }

    private fun recalculatePercentages(options: List<RouletteOption>) {
        val totalWeight = options.sumOf { it.weight }
        val updatedOptions = options.asSequence().map { option ->
            val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
            option.copy(percentage = String.format("%.2f", percent))
        }.toList()

        removeAllAndAddOptions(updatedOptions)
        _optionsLiveData.value = updatedOptions
    }

    fun toggleIsActive() {
        isActive = !isActive
        _isActiveLiveData.postValue(isActive)
    }

    fun onClickPreview() {
        _isLoading.value = true

        val items = mutableListOf<RoulettePreviewItem>()
        for (option in options) {
            if (option.title.trim().isEmpty()) {
                _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
                _isLoading.value = false
                return
            }

            items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
        }

        _roulettePreviewLiveData.postValue(RoulettePreview(can, items))
        _isLoading.value = false
    }

    fun createOrUpdateRoulette(onSuccess: (Boolean) -> Unit) {
        if (!_isLoading.value!!) {
            _isLoading.value = true

            val items = mutableListOf<RouletteItem>()
            for (option in options) {
                if (option.title.trim().isEmpty()) {
                    _toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
                    _isLoading.value = false
                    return
                }

                items.add(RouletteItem(title = option.title, weight = option.weight))
            }

            val request = CreateOrUpdateRouletteRequest(
                can = can,
                isActive = isActive,
                items = items
            )

            compositeDisposable.add(
                repository.createOrUpdateRoulette(
                    request = request,
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            _isLoading.value = false
                            if (it.success && it.data != null && it.data is Boolean) {
                                val message = if (it.data) {
                                    "룰렛을 활성화 했습니다."
                                } else {
                                    "룰렛을 비활성화 했습니다."
                                }
                                _toastLiveData.postValue(message)
                                onSuccess(it.data)
                            } else {
                                if (it.message != null) {
                                    _toastLiveData.postValue(it.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }
                        },
                        {
                            _isLoading.value = false
                            it.message?.let { message -> Logger.e(message) }
                            _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                        }
                    )
            )
        }
    }

    fun getRoulette() {
        if (!_isLoading.value!!) {
            _isLoading.value = true
            compositeDisposable.add(
                repository.getRoulette(
                    creatorId = SharedPreferenceManager.userId,
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            if (it.success) {
                                val data = it.data

                                if (data != null && data.items.isNotEmpty()) {
                                    _isActiveLiveData.value = data.isActive
                                    _canLiveData.value = data.can

                                    isActive = data.isActive
                                    can = data.can

                                    val options = data.items.asSequence().map { item ->
                                        RouletteOption(title = item.title, weight = item.weight)
                                    }.toList()
                                    removeAllAndAddOptions(options = options)
                                    recalculatePercentages(options)
                                } else {
                                    _isActiveLiveData.value = false
                                    _canLiveData.value = 0

                                    isActive = false
                                    can = 0

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

    private fun removeAllAndAddOptions(options: List<RouletteOption>) {
        this.options.clear()
        this.options.addAll(options)
    }
}
