package com.hyphenate.chatdemo.viewmodel

import androidx.lifecycle.viewModelScope
import com.hyphenate.chatdemo.DemoHelper
import com.hyphenate.chatdemo.common.LocalNotifyHelper
import com.hyphenate.chatdemo.common.room.entity.parse
import com.hyphenate.chatdemo.repository.ChatContactRepository
import com.hyphenate.chatdemo.utils.PhoneNumberUtils
import com.hyphenate.easeui.ChatUIKitClient
import com.hyphenate.easeui.common.ChatClient
import com.hyphenate.easeui.common.ChatContact
import com.hyphenate.easeui.common.ChatException
import com.hyphenate.easeui.common.ChatLog
import com.hyphenate.easeui.common.ChatValueCallback
import com.hyphenate.easeui.common.extensions.catchChatException
import com.hyphenate.easeui.common.extensions.toUser
import com.hyphenate.easeui.common.helper.ContactSortedHelper
import com.hyphenate.easeui.model.ChatUIKitProfile
import com.hyphenate.easeui.model.ChatUIKitUser
import com.hyphenate.easeui.model.setUserInitialLetter
import com.hyphenate.easeui.viewmodel.contacts.ChatUIKitContactListViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch

class ChatContactViewModel: ChatUIKitContactListViewModel() {
     private var contactRepository = ChatContactRepository()

    override fun loadData(fetchServerData: Boolean){
        viewModelScope.launch {
            if (fetchServerData) {
                flow {
                    emit(contactRepository.loadLocalContact())
                }
                .flatMapConcat {
                    val sortedList = it.map {
                            user -> user.setUserInitialLetter()
                            user
                        }
                        .let {list ->
                            ContactSortedHelper.sortedList(list).toMutableList()
                        }
                    view?.loadContactListSuccess(sortedList)
                    flow {
                        emit(contactRepository.loadData())
                    }
                }
            } else {
                flow {
                    emit(contactRepository.loadLocalContact())
                }
            }
                .catchChatException { e ->
                    view?.loadContactListFail(e.errorCode, e.description)
                }
                .collect {
                    ChatClient.getInstance().contactManager().asyncFetchAllContactsFromLocal(object :
                        ChatValueCallback<MutableList<ChatContact>> {
                        override fun onSuccess(value: MutableList<ChatContact>?) {
                            val contacts = value.orEmpty().associateBy { contact -> contact.username }
                            val data = it.map { user ->
                                val profile = DemoHelper.getInstance().getDataModel()
                                    .getUser(user.userId)?.parse()
                                    ?: ChatUIKitProfile(user.userId)
                                contacts[user.userId]?.remark
                                    ?.takeIf(String::isNotEmpty)
                                    ?.let { remark ->
                                        profile.remark = remark
                                        DemoHelper.getInstance().getDataModel()
                                            .insertUser(profile, false)
                                    }
                                profile
                            }
                            if (data.isNotEmpty()) {
                                ChatUIKitClient.updateUsersInfo(data)
                            }
                            val sortedList = data.map { profile ->
                                profile.toUser().apply {
                                    setUserInitialLetter()
                                }
                            }.let(ContactSortedHelper::sortedList)
                            viewModelScope.launch {
                                view?.loadContactListSuccess(sortedList.toMutableList())
                            }
                        }

                        override fun onError(error: Int, errorMsg: String?) {
                            ChatLog.e("ChatContactViewModel","asyncFetchAllContactsFromLocal onError $error $errorMsg")
                            viewModelScope.launch {
                                view?.loadContactListFail(error, errorMsg.orEmpty())
                            }
                        }
                    })
                }
        }
    }

    override fun fetchContactInfo(contactList: List<ChatUIKitUser>?) {
        contactList?.filter {
            val user = DemoHelper.getInstance().getDataModel().getUser(it.userId)
            (user == null || user.updateTimes == 0) &&
                    (it.nickname.isNullOrEmpty() || it.avatar.isNullOrEmpty())
        }?.apply {
            if (this.isNotEmpty()) {
                super.fetchContactInfo(this)
            }
        }
    }

    override fun addContact(userName: String, reason: String?) {
        viewModelScope.launch {
            flow {
                try {
                    if (PhoneNumberUtils.isPhoneNumber(userName)){
                        emit(contactRepository.checkPhoneNumOrIdFromServer(userName))
                    }else{
                        emit(contactRepository.addContact(userName,reason))
                    }
                }catch (e:ChatException){
                    inMainScope {
                        view?.addContactFail(e.errorCode,e.description)
                    }
                }
            }
            .flatMapConcat { username->
                flow<String> {
                    username?.let {
                        super.addContact(it, reason)
                    }
                }
            }
            .catchChatException { e->
                view?.addContactFail(e.errorCode,e.description)
            }
           .collect{
                LocalNotifyHelper.createContactNotifyMessage(it)
                view?.addContactSuccess(it)
            }
        }
    }


    private fun inMainScope(scope: ()->Unit) {
        viewModelScope.launch(context = Dispatchers.Main) {
            scope()
        }
    }
}
