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.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.*
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.entity.CommentDraft
import com.gh.gamecenter.feature.entity.CommentEntity
import com.gh.gamecenter.feature.entity.ForumVideoEntity
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.gh.gamecenter.room.dao.CommentDraftDao
import com.google.gson.reflect.TypeToken
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.JSONArray
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>>()

    var articleDetail: ArticleDetailEntity? = null
    var questionDetail: QuestionsDetailEntity? = null
    var videoDetail: ForumVideoEntity? = null

    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()
            ).zipWith(api.getCommunityArticleDetail(articleId)) { commentList, articleDetail ->
                this.articleDetail = articleDetail
                commentList
            }.map {
                val type = object : TypeToken<List<CommentEntity>>() {}.type
                GsonUtils.gson.fromJson(it.body()?.toJson() ?: "", type)
            }

            CommentType.COMMUNITY_ARTICLE_CONVERSATION -> api.getCommunityArticleCommentConversation(commentId, page)
                .zipWith(api.getCommunityArticleDetail(articleId)) { commentList, articleDetail ->
                    this.articleDetail = articleDetail
                    commentList
                }

            CommentType.VIDEO -> api.getVideoCommentList(videoId, page, mapOf())
                .zipWith(api.getBbsVideoDetail(videoId)) { commentList, videoDetail ->
                    this.videoDetail = videoDetail
                    commentList
                }
                .map {
                    val type = object : TypeToken<List<CommentEntity>>() {}.type
                    GsonUtils.gson.fromJson(it.body()?.toJson() ?: "", type)
                }

            CommentType.VIDEO_CONVERSATION -> api.getVideoCommentConversationList(videoId, commentId, page)
                .zipWith(api.getBbsVideoDetail(videoId)) { commentList, videoDetail ->
                    this.videoDetail = videoDetail
                    commentList
                }

            CommentType.COMMUNITY_QUESTION, CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                api.getQuestionsById(questionId)
                    .observeOn(Schedulers.io())
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .map {
                        this.questionDetail = it
                        emptyList()
                    }
            }

            else -> null
        }
    }

    /**
     * 获取帖子详情作为埋点数据源
     */
    @SuppressLint("CheckResult")
    fun getArticleDetail() {
        val api = RetrofitManager.getInstance().api

        when (commentType) {
            CommentType.COMMUNITY_ARTICLE,
            CommentType.COMMUNITY_ARTICLE_CONVERSATION -> {
                api.getCommunityArticleDetail(articleId)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({
                        this.articleDetail = it
                    }, {})
            }
            CommentType.VIDEO,
            CommentType.VIDEO_CONVERSATION -> {
                api.getBbsVideoDetail(videoId)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({
                        this.videoDetail = it
                    }, {})
            }
            CommentType.COMMUNITY_QUESTION,
            CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                api.getQuestionsById(questionId)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({
                        this.questionDetail = it
                    }, {})
            }
            else -> {}
        }
    }

    fun trackArticleComment(reply: Boolean) {
        when (commentType) {
            CommentType.COMMUNITY_QUESTION,
            CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                questionDetail?.let {
                    if (reply)
                    {
                        SensorsBridge.trackArticleReply(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id ?: "",
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "提问帖"
                        )
                    } else {
                        SensorsBridge.trackArticleComment(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id ?: "",
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "提问帖"
                        )
                    }
                }
            }

            CommentType.COMMUNITY_ARTICLE,
            CommentType.COMMUNITY_ARTICLE_CONVERSATION -> {
                articleDetail?.let {
                    if (reply) {
                        SensorsBridge.trackArticleReply(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "帖子"
                        )
                    } else {
                        SensorsBridge.trackArticleComment(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "帖子"
                        )
                    }
                }
            }

            CommentType.VIDEO,
            CommentType.VIDEO_CONVERSATION -> {
                videoDetail?.let {
                    if (reply) {
                        SensorsBridge.trackArticleReply(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.bbs?.id ?: "",
                            bbsType = it.bbs?.typeChinese ?: "",
                            activityTag = it.tagActivityName,
                            gameForumType = it.bbs?.game?.categoryChinese ?: "",
                            articleType = "视频贴"
                        )
                    } else {
                        SensorsBridge.trackArticleComment(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.bbs?.id ?: "",
                            bbsType = it.bbs?.typeChinese ?: "",
                            activityTag = it.tagActivityName,
                            gameForumType = it.bbs?.game?.categoryChinese ?: "",
                            articleType = "视频贴"
                        )
                    }
                }
            }

            else -> {}
        }
    }

    fun trackArticleCommentResult(reply: Boolean, result: String) {
        when (commentType) {
            CommentType.COMMUNITY_QUESTION,
            CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
                questionDetail?.let {
                    if (reply) {
                        SensorsBridge.trackArticleReplyResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id ?: "",
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "提问帖",
                            result = result
                        )
                    } else {
                        SensorsBridge.trackArticleCommentResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id ?: "",
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "提问帖",
                            result = result
                        )
                    }
                }
            }

            CommentType.COMMUNITY_ARTICLE,
            CommentType.COMMUNITY_ARTICLE_CONVERSATION -> {
                articleDetail?.let {
                    if (reply) {
                        SensorsBridge.trackArticleReplyResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "帖子",
                            result = result
                        )
                    } else {
                        SensorsBridge.trackArticleCommentResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.community.id,
                            bbsType = it.community.typeChinese,
                            activityTag = it.tagActivityName,
                            gameForumType = it.community.game?.categoryChinese ?: "",
                            articleType = "帖子",
                            result = result
                        )
                    }
                }
            }

            CommentType.VIDEO,
            CommentType.VIDEO_CONVERSATION -> {
                videoDetail?.let {
                    if (reply) {
                        SensorsBridge.trackArticleReplyResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.bbs?.id ?: "",
                            bbsType = it.bbs?.typeChinese ?: "",
                            activityTag = it.tagActivityName,
                            gameForumType = it.bbs?.game?.categoryChinese ?: "",
                            articleType = "视频贴",
                            result = result
                        )
                    } else {
                        SensorsBridge.trackArticleCommentResult(
                            customerType = it.user.auth?.text ?: "",
                            articleId = it.id,
                            bbsId = it.bbs?.id ?: "",
                            bbsType = it.bbs?.typeChinese ?: "",
                            activityTag = it.tagActivityName,
                            gameForumType = it.bbs?.game?.categoryChinese ?: "",
                            articleType = "视频贴",
                            result = result
                        )
                    }
                }
            }

            else -> {}
        }
    }

    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>()
                    val data = response?.string()?.toString()
                    apiResponse.data = if (data.isNullOrEmpty()) JSONObject() else JSONObject(data)
                    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
                            )
                        )
                    }

                    trackArticleCommentResult(commentEntity != null, "评论成功")
                }

                override fun onFailure(e: HttpException?) {
                    val apiResponse = ApiResponse<JSONObject>()
                    if (e is HttpException) {
                        apiResponse.httpException = e
                        mPostCommentLiveData.postValue(apiResponse)
                    } else {
                        mPostCommentLiveData.postValue(apiResponse)
                    }
                    trackArticleCommentResult(commentEntity != null, "评论失败")
                }
            })
    }

    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)
    }
}