package kr.co.vividnext.sodalive.live

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable
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 kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationResponse
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
import kr.co.vividnext.sodalive.live.room.EnterOrQuitLiveRoomRequest
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
import kr.co.vividnext.sodalive.live.room.StartLiveRequest
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
import kr.co.vividnext.sodalive.settings.event.EventItem
import kr.co.vividnext.sodalive.settings.event.EventRepository

class LiveViewModel(
    private val repository: LiveRepository,
    private val eventRepository: EventRepository,
    private val liveRecommendRepository: LiveRecommendRepository,
    private val creatorCommunityRepository: CreatorCommunityRepository
) : 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 _recommendLiveData = MutableLiveData<List<GetRecommendLiveResponse>>()
    val recommendLiveData: LiveData<List<GetRecommendLiveResponse>>
        get() = _recommendLiveData

    private val _isFollowedCreatorLive = MutableLiveData(
        SharedPreferenceManager.isFollowedCreatorLive
    )
    val isFollowedCreatorLive: LiveData<Boolean>
        get() = _isFollowedCreatorLive

    private val _recommendChannelLiveData = MutableLiveData<List<GetRecommendChannelResponse>>()
    val recommendChannelLiveData: LiveData<List<GetRecommendChannelResponse>>
        get() = _recommendChannelLiveData

    private val _liveNowLiveData = MutableLiveData<List<GetRoomListResponse>>()
    val liveNowLiveData: LiveData<List<GetRoomListResponse>>
        get() = _liveNowLiveData

    private val _liveReservationLiveData = MutableLiveData<List<GetRoomListResponse>>()
    val liveReservationLiveData: LiveData<List<GetRoomListResponse>>
        get() = _liveReservationLiveData

    private val _eventLiveData = MutableLiveData<List<EventItem>>()
    val eventLiveData: LiveData<List<EventItem>>
        get() = _eventLiveData

    private val _communityPostItemLiveData = MutableLiveData<List<GetCommunityPostListResponse>>()
    val communityPostItemLiveData: LiveData<List<GetCommunityPostListResponse>>
        get() = _communityPostItemLiveData

    var page = 1
    var isLast = false
    private val pageSize = 10

    fun toggleIsFollowedCreatorLive() {
        val isOn = !_isFollowedCreatorLive.value!!
        SharedPreferenceManager.isFollowedCreatorLive = isOn
        _isFollowedCreatorLive.value = isOn
        if (_isFollowedCreatorLive.value!!) {
            getFollowedChannelList()
        } else {
            getRecommendChannelList()
        }
    }

    private fun getFollowedChannelList() {
        compositeDisposable.add(
            liveRecommendRepository.getFollowingChannelList(
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success && it.data != null) {
                            _recommendChannelLiveData.postValue(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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    private fun getRecommendChannelList() {
        compositeDisposable.add(
            liveRecommendRepository.getRecommendChannelList(
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success && it.data != null) {
                            _recommendChannelLiveData.postValue(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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    private fun getLatestPostListFromCreatorsYouFollow() {
        compositeDisposable.add(
            creatorCommunityRepository.getLatestPostListFromCreatorsYouFollow(
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success && it.data != null) {
                            _communityPostItemLiveData.postValue(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 getSummary() {
        if (!_isLoading.value!!) {
            if (_isFollowedCreatorLive.value!!) {
                getFollowedChannelList()
            } else {
                getRecommendChannelList()
            }
            getLatestPostListFromCreatorsYouFollow()

            val liveNow = repository.roomList(
                status = LiveRoomStatus.NOW,
                page = 1,
                size = pageSize,
                token = "Bearer ${SharedPreferenceManager.token}"
            )

            val liveReservation = repository.roomList(
                status = LiveRoomStatus.RESERVATION,
                page = 1,
                size = pageSize,
                token = "Bearer ${SharedPreferenceManager.token}"
            )

            val event = eventRepository.getEvents(
                0,
                5,
                token = "Bearer ${SharedPreferenceManager.token}"
            )

            val recommendLive = liveRecommendRepository.getRecommendLive(
                token = "Bearer ${SharedPreferenceManager.token}"
            )

            _isLoading.postValue(true)

            compositeDisposable.add(
                Flowable.combineLatest(
                    liveNow,
                    liveReservation,
                    event,
                    recommendLive,
                ) { t1, t2, t3, t4 -> LiveSummary(t1, t2, t3, t4) }
                    .subscribe(
                        {
                            val now = it.liveNow
                            if (now.success && now.data != null) {
                                _liveNowLiveData.postValue(now.data!!)
                                if (now.data.isNotEmpty()) {
                                    page += 1
                                } else {
                                    isLast = true
                                }
                            } else {
                                if (now.message != null) {
                                    _toastLiveData.postValue(now.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }

                            val reservation = it.liveReservation
                            if (reservation.success && reservation.data != null) {
                                _liveReservationLiveData.postValue(reservation.data!!)
                                if (reservation.data.isNotEmpty()) {
                                    page += 1
                                } else {
                                    isLast = true
                                }
                            } else {
                                if (reservation.message != null) {
                                    _toastLiveData.postValue(reservation.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }

                            val eventResponse = it.event
                            if (eventResponse.success && eventResponse.data != null) {
                                val data = eventResponse.data
                                _eventLiveData.postValue(data.eventList)
                            } else {
                                _eventLiveData.postValue(emptyList())
                            }

                            val recommendLiveResponse = it.recommendLive
                            if (
                                recommendLiveResponse.success &&
                                recommendLiveResponse.data != null
                            ) {
                                val data = recommendLiveResponse.data
                                _recommendLiveData.postValue(data!!)
                            } else {
                                _recommendLiveData.postValue(emptyList())
                            }

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

    fun quitRoom(roomId: Long, onSuccess: () -> Unit) {
        _isLoading.value = true
        compositeDisposable.add(
            repository.quitRoom(roomId, "Bearer ${SharedPreferenceManager.token}")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success) {
                            onSuccess()
                            _isLoading.value = false
                        } else {
                            _isLoading.value = false
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                )
                            }
                        }
                    },
                    {
                        _isLoading.value = false
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    fun startLive(roomId: Long, onEnterRoomSuccess: () -> Unit) {
        _isLoading.value = true
        compositeDisposable.add(
            repository.startLive(
                StartLiveRequest(roomId),
                "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        _isLoading.value = false
                        if (it.success) {
                            enterRoom(roomId, onEnterRoomSuccess)
                        } 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 cancelLive(roomId: Long, reason: String, onSuccess: () -> Unit) {
        _isLoading.postValue(true)

        compositeDisposable.add(
            repository.cancelLive(
                CancelLiveRequest(roomId, reason),
                "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success) {
                            _isLoading.value = false
                            onSuccess()
                        } else {
                            _isLoading.value = false
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                )
                            }
                        }
                    },
                    {
                        _isLoading.value = false
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    fun enterRoom(roomId: Long, onSuccess: () -> Unit, password: String? = null) {
        _isLoading.value = true
        val request = EnterOrQuitLiveRoomRequest(roomId, password = password)
        compositeDisposable.add(
            repository.enterRoom(request, "Bearer ${SharedPreferenceManager.token}")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        if (it.success) {
                            _isLoading.value = false
                            onSuccess()
                        } else {
                            _isLoading.value = false
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                )
                            }
                        }
                    },
                    {
                        _isLoading.value = false
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                    }
                )
        )
    }

    fun getRoomDetail(roomId: Long, onSuccess: (GetRoomDetailResponse) -> Unit) {
        _isLoading.value = true
        compositeDisposable.add(
            repository.getRoomDetail(
                roomId = roomId,
                token = "Bearer ${SharedPreferenceManager.token}"
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        _isLoading.value = false
                        if (it.success && it.data != null) {
                            onSuccess(it.data)
                        } else {
                            if (it.message != null) {
                                _toastLiveData.postValue(it.message)
                            } else {
                                _toastLiveData.postValue(
                                    "라이브 정보를 가져오지 못했습니다.\n다시 시도해 주세요."
                                )
                            }
                        }
                    },
                    {
                        _isLoading.value = false
                        it.message?.let { message -> Logger.e(message) }
                        _toastLiveData.postValue(
                            "라이브 정보를 가져오지 못했습니다.\n다시 시도해 주세요."
                        )
                    }
                )
        )
    }

    fun reservationRoom(
        roomId: Long,
        password: String? = null,
        onSuccess: (MakeLiveReservationResponse) -> Unit
    ) {
        _isLoading.value = true
        compositeDisposable.add(
            repository.makeReservation(
                MakeLiveReservationRequest(roomId = roomId, password = password),
                "Bearer ${SharedPreferenceManager.token}"
            )
                .retry(3)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                    {
                        _isLoading.value = false
                        if (it.success && it.data != null) {
                            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 getLiveNow() {
        if (!isLast && !_isLoading.value!!) {
            _isLoading.postValue(true)
            compositeDisposable.add(
                repository.roomList(
                    status = LiveRoomStatus.NOW,
                    page = page,
                    size = pageSize,
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            _isLoading.postValue(false)
                            if (it.success && it.data != null) {
                                _liveNowLiveData.postValue(it.data!!)
                                if (it.data.isNotEmpty()) {
                                    page += 1
                                } else {
                                    isLast = true
                                }
                            } else {
                                if (it.message != null) {
                                    _toastLiveData.postValue(it.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }
                        },
                        {
                            _isLoading.postValue(false)
                            it.message?.let { message -> Logger.e(message) }
                            _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                        }
                    )
            )
        }
    }

    fun getLiveReservation(dateString: String? = null) {
        if (!isLast && !_isLoading.value!!) {
            _isLoading.postValue(true)
            compositeDisposable.add(
                repository.roomList(
                    dateString = dateString,
                    status = LiveRoomStatus.RESERVATION,
                    page = page,
                    size = pageSize,
                    token = "Bearer ${SharedPreferenceManager.token}"
                )
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                        {
                            _isLoading.postValue(false)
                            if (it.success && it.data != null) {
                                _liveReservationLiveData.postValue(it.data!!)
                                if (it.data.isNotEmpty()) {
                                    page += 1
                                } else {
                                    isLast = true
                                }
                            } else {
                                if (it.message != null) {
                                    _toastLiveData.postValue(it.message)
                                } else {
                                    _toastLiveData.postValue(
                                        "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
                                    )
                                }
                            }
                        },
                        {
                            _isLoading.postValue(false)
                            it.message?.let { message -> Logger.e(message) }
                            _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
                        }
                    )
            )
        }
    }
}
