/*
 * F7cloud Talk - Android Client
 *
 * SPDX-FileCopyrightText: 2023 Marcel Hibbe <dev@mhibbe.de>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package ru.f7cloud.talk.conversationinfoedit.viewmodel

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import ru.f7cloud.talk.chat.data.network.ChatNetworkDataSource
import ru.f7cloud.talk.conversationinfoedit.data.ConversationInfoEditRepository
import ru.f7cloud.talk.data.user.model.User
import ru.f7cloud.talk.models.domain.ConversationModel
import ru.f7cloud.talk.utils.ApiUtils
import ru.f7cloud.talk.utils.database.user.CurrentUserProviderOld
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.launch
import java.io.File
import javax.inject.Inject

class ConversationInfoEditViewModel @Inject constructor(
    private val repository: ChatNetworkDataSource,
    private val conversationInfoEditRepository: ConversationInfoEditRepository,
    private val currentUserProvider: CurrentUserProviderOld
) : ViewModel() {

    sealed interface ViewState

    object GetRoomStartState : ViewState
    object GetRoomErrorState : ViewState
    open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState

    object UploadAvatarErrorState : ViewState
    open class UploadAvatarSuccessState(val conversationModel: ConversationModel) : ViewState

    object DeleteAvatarErrorState : ViewState
    open class DeleteAvatarSuccessState(val conversationModel: ConversationModel) : ViewState

    private val _viewState: MutableLiveData<ViewState> = MutableLiveData(GetRoomStartState)
    val viewState: LiveData<ViewState>
        get() = _viewState

    private val _renameRoomUiState = MutableLiveData<RenameRoomUiState>(RenameRoomUiState.None)
    val renameRoomUiState: LiveData<RenameRoomUiState>
        get() = _renameRoomUiState

    private val _setConversationDescriptionUiState =
        MutableLiveData<SetConversationDescriptionUiState>(SetConversationDescriptionUiState.None)
    val setConversationDescriptionUiState: LiveData<SetConversationDescriptionUiState>
        get() = _setConversationDescriptionUiState

    private val currentUser = currentUserProvider.currentUser.blockingGet()

    val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)

    fun getRoom(user: User, token: String) {
        _viewState.value = GetRoomStartState
        repository.getRoom(user, token)
            .subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe(GetRoomObserver())
    }

    fun uploadConversationAvatar(user: User, file: File, roomToken: String) {
        val url = ApiUtils.getUrlForConversationAvatar(1, user.baseUrl!!, roomToken)

        conversationInfoEditRepository.uploadConversationAvatar(
            credentials,
            url,
            user,
            file,
            roomToken
        )
            .subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe(UploadConversationAvatarObserver())
    }

    fun deleteConversationAvatar(user: User, roomToken: String) {
        val url = ApiUtils.getUrlForConversationAvatar(1, user.baseUrl!!, roomToken)

        conversationInfoEditRepository.deleteConversationAvatar(
            credentials,
            url,
            user,
            roomToken
        )
            .subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe(DeleteConversationAvatarObserver())
    }

    @Suppress("Detekt.TooGenericExceptionCaught")
    fun renameRoom(roomToken: String, newRoomName: String) {
        viewModelScope.launch {
            try {
                val apiVersion = ApiUtils.getConversationApiVersion(
                    currentUser,
                    intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)
                )
                val url = ApiUtils.getUrlForRoom(
                    apiVersion,
                    currentUser.baseUrl!!,
                    roomToken
                )

                conversationInfoEditRepository.renameConversation(
                    credentials,
                    url,
                    roomToken,
                    newRoomName
                )
                _renameRoomUiState.value = RenameRoomUiState.Success
            } catch (exception: Exception) {
                _renameRoomUiState.value = RenameRoomUiState.Error(exception)
            }
        }
    }

    @Suppress("Detekt.TooGenericExceptionCaught")
    fun setConversationDescription(roomToken: String, conversationDescription: String?) {
        viewModelScope.launch {
            try {
                val apiVersion = ApiUtils.getConversationApiVersion(
                    currentUser,
                    intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)
                )
                val url = ApiUtils.getUrlForConversationDescription(
                    apiVersion,
                    currentUser.baseUrl!!,
                    roomToken
                )

                conversationInfoEditRepository.setConversationDescription(
                    credentials,
                    url,
                    roomToken,
                    conversationDescription
                )

                _setConversationDescriptionUiState.value = SetConversationDescriptionUiState.Success
            } catch (exception: Exception) {
                _setConversationDescriptionUiState.value = SetConversationDescriptionUiState.Error(exception)
            }
        }
    }

    inner class GetRoomObserver : Observer<ConversationModel> {
        override fun onSubscribe(d: Disposable) {
            // unused atm
        }

        override fun onNext(conversationModel: ConversationModel) {
            _viewState.value = GetRoomSuccessState(conversationModel)
        }

        override fun onError(e: Throwable) {
            Log.e(TAG, "Error when fetching room")
            _viewState.value = GetRoomErrorState
        }

        override fun onComplete() {
            // unused atm
        }
    }

    inner class UploadConversationAvatarObserver : Observer<ConversationModel> {
        override fun onSubscribe(d: Disposable) {
            // unused atm
        }

        override fun onNext(conversationModel: ConversationModel) {
            _viewState.value = UploadAvatarSuccessState(conversationModel)
        }

        override fun onError(e: Throwable) {
            Log.e(TAG, "Error when uploading avatar")
            _viewState.value = UploadAvatarErrorState
        }

        override fun onComplete() {
            // unused atm
        }
    }

    inner class DeleteConversationAvatarObserver : Observer<ConversationModel> {
        override fun onSubscribe(d: Disposable) {
            // unused atm
        }

        override fun onNext(conversationModel: ConversationModel) {
            _viewState.value = DeleteAvatarSuccessState(conversationModel)
        }

        override fun onError(e: Throwable) {
            Log.e(TAG, "Error when deleting avatar")
            _viewState.value = DeleteAvatarErrorState
        }

        override fun onComplete() {
            // unused atm
        }
    }

    companion object {
        private val TAG = ConversationInfoEditViewModel::class.simpleName
    }

    sealed class RenameRoomUiState {
        data object None : RenameRoomUiState()
        data object Success : RenameRoomUiState()
        data class Error(val exception: Exception) : RenameRoomUiState()
    }

    sealed class SetConversationDescriptionUiState {
        data object None : SetConversationDescriptionUiState()
        data object Success : SetConversationDescriptionUiState()
        data class Error(val exception: Exception) : SetConversationDescriptionUiState()
    }
}
