package com.gh.gamecenter.qa.comment

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.common.utils.UploadImageUtils
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.retrofit.ApiResponse
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.syncpage.SyncDataEntity
import com.gh.gamecenter.common.syncpage.SyncFieldConstants
import com.gh.gamecenter.common.syncpage.SyncPageRepository
import com.gh.gamecenter.common.utils.createRequestBodyAny
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.common.utils.tryWithDefaultCatch
import com.gh.gamecenter.energy.EnergyBridge
import com.gh.gamecenter.entity.CommentDraft
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.gh.gamecenter.room.dao.CommentDraftDao
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException

open class NewCommentViewModel(
    application: Application,
    var answerId: String = "",
    var commentId: String = "",
    var articleId: String = "",
    var communityId: String = "",
    var videoId: String = "",
    var questionId: String = "",
    var gameCollectionId: String = "",
    var rootCommentId: String = "",
    var commentType: CommentType = CommentType.ANSWER,
    var isVideoAuthor: Boolean = false
) : ListViewModel<CommentEntity, CommentEntity>(application) {

    private val mPostCommentLiveData = MutableLiveData<ApiResponse<JSONObject>>()

    var commentDraftDao: CommentDraftDao? = null

    val postCommentLiveData: LiveData<ApiResponse<JSONObject>>
        get() = mPostCommentLiveData
    val deleteVideoCommentLiveData = MutableLiveData<CommentEntity?>()
    val pictureList = ArrayList<String>()
    val pictureLiveData = MutableLiveData<ArrayList<String>>()

    init {
        commentDraftDao = AppDatabase.getInstance().commentDraftDao()
    }

    override fun provideDataObservable(page: Int): Observable<List<CommentEntity>>? {
        val api = RetrofitManager.getInstance().api

        return when (commentType) {
            CommentType.ANSWER -> api.getAnswerCommentList(answerId, page)
            CommentType.ANSWER_CONVERSATION -> api.getAnswerCommentConversationList(answerId, commentId, page)

            CommentType.COMMUNITY_ARTICLE -> api.getCommunityArticleCommentList(
                articleId,
                "time.create:1",
                page,
                mapOf()
            )
            CommentType.COMMUNITY_ARTICLE_CONVERSATION -> api.getCommunityArticleCommentConversation(commentId, page)

            CommentType.VIDEO -> api.getVideoCommentList(videoId, page, mapOf())
            CommentType.VIDEO_CONVERSATION -> api.getVideoCommentConversationList(videoId, commentId, page)
            else -> null
        }
    }

    fun postPictureAndComment(content: String, commentEntity: CommentEntity?) {
        if (pictureList.isNotEmpty()) {
            UploadImageUtils.compressAndUploadImageList(
                UploadImageUtils.UploadType.comment, pictureList, false,
                object : UploadImageUtils.OnUploadImageListListener {
                    override fun onSuccess(imageUrlMap: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) {
                        if (errorMap.isNotEmpty()) {
                            uploadPictureFail(errorMap)
                        } else {
                            val imageUrls = imageUrlMap.map { it.value }.toList()
                            postComment(content, imageUrls, commentEntity)
                        }
                    }

                    override fun onCompressSuccess(imageUrls: List<String>) {
                        super.onCompressSuccess(imageUrls)
                        pictureList.clear()
                        pictureList.addAll(imageUrls)
                    }

                    override fun onSingleSuccess(imageUrlMap: Map<String, String>) {}

                    override fun onError(errorMap: Map<String, Exception>) {
                        uploadPictureFail(errorMap)
                    }

                    override fun onProgress(total: Long, progress: Long) {}
                })
        } else {
            postComment(content, null, commentEntity)
        }
    }

    private fun uploadPictureFail(errorMap: Map<String, Exception>) {
        for (path in errorMap.keys) {
            pictureList.remove(path)
        }
        pictureLiveData.postValue(pictureList)
        mPostCommentLiveData.postValue(ApiResponse<JSONObject>())
        Utils.toast(getApplication(), "图片上传失败")
    }

    fun postComment(content: String, imageUrls: List<String>?, commentEntity: CommentEntity?) {
        val api = RetrofitManager.getInstance().api
        val requestMap = hashMapOf<String, Any>()
        requestMap["content"] = content
        if (!imageUrls.isNullOrEmpty()) {
            requestMap["images"] = imageUrls
        }
        if (gameCollectionId.isNotEmpty() && commentEntity != null) {
            requestMap["root"] = rootCommentId
        }

        val body = requestMap.createRequestBodyAny()
        val observable =
            when (commentType) {
                CommentType.ANSWER, CommentType.ANSWER_CONVERSATION -> {
                    if (commentEntity == null) {
                        api.postNewCommentToAnswer(answerId, body)
                    } else {
                        api.postReplyToAnswerComment(answerId, commentEntity.id, body)
                    }
                }

                CommentType.COMMUNITY_ARTICLE, CommentType.COMMUNITY_ARTICLE_CONVERSATION -> {
                    if (commentEntity == null) {
                        api.postCommentToCommunityArticle(articleId, body)
                    } else {
                        api.postReplyToCommunityArticleComment(commentEntity.id, body)
                    }
                }

                CommentType.COMMUNITY_QUESTION, CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                    if (commentEntity == null) {
                        api.postQuestionComment(questionId, body)
                    } else {
                        api.postReplyToQuestionComment(questionId, commentEntity.id, body)
                    }
                }

                CommentType.VIDEO, CommentType.VIDEO_CONVERSATION -> {
                    if (commentEntity == null) {
                        api.postNewCommentToVideo(videoId, body)
                    } else {
                        api.postReplyToVideoComment(videoId, commentEntity.id, body)
                    }
                }

                CommentType.GAME_COLLECTION, CommentType.GAME_COLLECTION_CONVERSATION -> {
                    if (commentEntity == null) {
                        api.postGameCollectionComment(gameCollectionId, body)
                    } else {
                        api.postReplyToGameCollectionComment(gameCollectionId, commentEntity.id, body)
                    }
                }
            }

        // TODO Remove this apiResponse crap.
        observable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ResponseBody>() {
                override fun onResponse(response: ResponseBody?) {
                    pictureList.clear()
                    deleteCommentDraft(commentEntity)

                    val apiResponse = ApiResponse<JSONObject>()
                    apiResponse.data = JSONObject()
                    mPostCommentLiveData.postValue(apiResponse)

                    commentEntity?.id?.let {
                        SyncPageRepository.postSyncData(
                            SyncDataEntity(
                                it,
                                SyncFieldConstants.ARTICLE_COMMENT_REPLY_COUNT,
                                commentEntity.reply + 1
                            )
                        )
                        SyncPageRepository.postSyncData(
                            SyncDataEntity(
                                it,
                                SyncFieldConstants.ANSWER_COMMENT_REPLY_COUNT,
                                commentEntity.reply + 1,
                                checkFieldEntity = true
                            )
                        )
                    }

                    if (commentType == CommentType.COMMUNITY_ARTICLE && commentEntity == null) {
                        tryWithDefaultCatch {
                            EnergyBridge.postEnergyTask(
                                "comment_community_article",
                                JSONObject(response?.string()).optString("_id")
                            )
                        }
                    }

                    if (commentType == CommentType.VIDEO && commentEntity == null) {
                        tryWithDefaultCatch {
                            EnergyBridge.postEnergyTask(
                                "comment_video",
                                JSONObject(response?.string()).optString("_id")
                            )
                        }
                    }
                }

                override fun onFailure(e: HttpException?) {
                    val apiResponse = ApiResponse<JSONObject>()
                    if (e is HttpException) {
                        apiResponse.httpException = e
                        mPostCommentLiveData.postValue(apiResponse)
                    } else {
                        mPostCommentLiveData.postValue(apiResponse)
                    }
                }
            })
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
    }

    fun getCommentDraft(commentEntity: CommentEntity?): CommentDraft? {
        return when {
            commentEntity != null -> {
                commentDraftDao?.getDraftById(commentEntity.id ?: "")
            }
            commentType == CommentType.ANSWER || commentType == CommentType.ANSWER_CONVERSATION -> {
                commentDraftDao?.getDraftById(answerId)
            }
            commentType == CommentType.COMMUNITY_ARTICLE || commentType == CommentType.COMMUNITY_ARTICLE_CONVERSATION -> {
                commentDraftDao?.getDraftById(articleId)
            }
            commentType == CommentType.COMMUNITY_QUESTION || commentType == CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                commentDraftDao?.getDraftById(questionId)
            }
            commentType == CommentType.VIDEO || commentType == CommentType.VIDEO_CONVERSATION -> {
                commentDraftDao?.getDraftById(videoId)
            }
            commentType == CommentType.GAME_COLLECTION || commentType == CommentType.GAME_COLLECTION_CONVERSATION -> {
                commentDraftDao?.getDraftById(gameCollectionId)
            }
            else -> return null
        }
    }

    fun saveCommentDraft(commentEntity: CommentEntity?, draftContent: String) {
        // 保存/删除评论草稿
        commentDraftDao?.let {
            var id = commentEntity?.id ?: ""
            if (id.isEmpty()) {
                if (commentType == CommentType.COMMUNITY_ARTICLE || commentType == CommentType.COMMUNITY_ARTICLE_CONVERSATION) {
                    id = articleId
                }
                if (commentType == CommentType.ANSWER || commentType == CommentType.ANSWER_CONVERSATION) {
                    id = answerId
                }
                if (commentType == CommentType.COMMUNITY_QUESTION || commentType == CommentType.COMMUNITY_QUESTION_CONVERSATION) {
                    id = questionId
                }
                if (commentType == CommentType.VIDEO || commentType == CommentType.VIDEO_CONVERSATION) {
                    id = videoId
                }
                if (commentType == CommentType.GAME_COLLECTION || commentType == CommentType.GAME_COLLECTION_CONVERSATION) {
                    id = gameCollectionId
                }
            }

            if (draftContent.isNotEmpty() || pictureList.isNotEmpty()) {
                val draft = CommentDraft(id = id, draft = draftContent, pictureList = pictureList)
                if (it.updateDraft(draft) <= 0) {
                    tryCatchInRelease { it.addDraft(draft) }
                }
            } else {
                it.deleteDraftById(id)
            }
        }
    }

    fun deleteCommentDraft(commentEntity: CommentEntity?) {
        var id = commentEntity?.id ?: ""
        if (id.isEmpty()) {
            if (commentType == CommentType.COMMUNITY_ARTICLE || commentType == CommentType.COMMUNITY_ARTICLE_CONVERSATION) {
                id = articleId
            }

            if (commentType == CommentType.ANSWER || commentType == CommentType.ANSWER_CONVERSATION) {
                id = answerId
            }

            if (commentType == CommentType.COMMUNITY_QUESTION || commentType == CommentType.COMMUNITY_QUESTION_CONVERSATION) {
                id = questionId
            }

            if (commentType == CommentType.VIDEO || commentType == CommentType.VIDEO_CONVERSATION) {
                id = videoId
            }

            if (commentType == CommentType.GAME_COLLECTION || commentType == CommentType.GAME_COLLECTION_CONVERSATION) {
                id = gameCollectionId
            }
        }
        commentDraftDao?.deleteDraftById(id)
    }

    @SuppressLint("CheckResult")
    fun deleteVideoComment(entity: CommentEntity) {
        RetrofitManager.getInstance().api
            .deleteVideoComment(entity.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    deleteVideoCommentLiveData.postValue(entity)
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    deleteVideoCommentLiveData.postValue(null)
                }
            })
    }

    fun getCommentReply(
        videoId: String,
        commentId: String,
        page: Int,
        resultCallback: (result: ArrayList<CommentEntity>) -> Unit
    ) {
        RetrofitManager.getInstance().api
            .getVideoCommentReply(videoId, commentId, page)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ArrayList<CommentEntity>>() {
                override fun onResponse(response: ArrayList<CommentEntity>?) {
                    super.onResponse(response)
                    if (response != null) {
                        resultCallback.invoke(response)
                    }
                }
            })
    }


    class Factory(
        private val application: Application,
        private val answerId: String = "",
        private val commentId: String = "",
        private val articleId: String = "",
        private val communityId: String = "",
        private val videoId: String = "",
        private val questionId: String = "",
        private val gameCollectionId: String = "",
        private val rootCommentId: String = "",
        private val isVideoAuthor: Boolean = false,
        private val commentType: CommentType
    ) : ViewModelProvider.NewInstanceFactory() {

        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return NewCommentViewModel(
                application = application,
                answerId = answerId,
                articleId = articleId,
                communityId = communityId,
                videoId = videoId,
                questionId = questionId,
                gameCollectionId = gameCollectionId,
                commentId = commentId,
                rootCommentId = rootCommentId,
                commentType = commentType,
                isVideoAuthor = isVideoAuthor
            ) as T
        }
    }
}

enum class CommentType {
    ANSWER,
    ANSWER_CONVERSATION,

    COMMUNITY_ARTICLE,
    COMMUNITY_ARTICLE_CONVERSATION,

    COMMUNITY_QUESTION,
    COMMUNITY_QUESTION_CONVERSATION,

    VIDEO,
    VIDEO_CONVERSATION,

    GAME_COLLECTION,
    GAME_COLLECTION_CONVERSATION;

    fun isVideo(): Boolean {
        return (this == VIDEO || this == VIDEO_CONVERSATION)
    }
}