import operator
import datetime
from django.db.models import Q, Sum, Count, F
from django.utils import timezone

from gm_types.error import ERROR
from gm_types.mimas import (
    TRACTATE_PLATFORM,
    TRACTATE_REPLY_HIGHLIGHT
)
from gm_dataquery.dict_mixin import to_dict

from .base import BaseService
from utils.rpc import gen
from talos.libs.datetime_utils import get_timestamp_or_none
from talos.models.soft_article.reply import SoftArticleReply
from talos.models.soft_article.soft_article import SoftArticle, SoftArticleExtra
from talos.cache.base import soft_article_reply_count, soft_article_vote_count_cache


class SoftArticleReplyService(BaseService):

    model = SoftArticleReply

    TOP_ID_NULL = 0
    REPIED_ID_NULL = 0
    reply_cache_key = 'soft_article_{top_id}_reply_num'

    @classmethod
    def inc_reply_vote(cls, reply):
        tr = SoftArticleReply.objects.get(id=reply.id)
        tr.vote_num = F('vote_num') + 1
        tr.save(update_fields=['vote_num'])
        return soft_article_vote_count_cache.incrby(str(reply.id), 1)

    @classmethod
    def dec_reply_vote(cls, reply):
        tr = SoftArticleReply.objects.get(id=reply.id)
        if tr.vote_num > 0:
            tr.vote_num = F('vote_num') - 1
            tr.save(update_fields=['vote_num'])
        vote_cache_count = int(soft_article_vote_count_cache.get(str(reply.id)) or 0)
        if vote_cache_count > 0:
            return soft_article_vote_count_cache.decr(str(reply.id), 1)
        return vote_cache_count

    @classmethod
    def healthy(cls, reply_id):
        if not reply_id:
            gen(ERROR.PARAMS_INCOMPLETE)

        reply = cls.get_by_id(pk=reply_id)

        if not reply:
            return gen(ERROR.TRACTATEREPLY_NOT_FOUND)

        if not reply.is_online:
            return gen(ERROR.TRACTATEREPLY_OFF_LINE)

        return reply

    @classmethod
    def get_replies_info(cls, reply_ids):
        replies = cls.model.objects.filter(pk__in=reply_ids)
        result = {}
        for item in replies:
            result[item.id] = to_dict(item)
            result[item.id]['create_time'] = int(get_timestamp_or_none(item.create_time))
            result[item.id]['update_time'] = int(get_timestamp_or_none(item.update_time))

        return result

    @classmethod
    def list_top_reply_by_soft_article_ids(cls, soft_article_ids, offset, count):
        """一组帖子的一级评论"""
        result = {}
        for soft_article_id in soft_article_ids:
            result[soft_article_id] = cls.list_top_reply_by_soft_article_id(soft_article_id=soft_article_id,
                                                                            offset=offset,
                                                                            count=count)
        return result

    @classmethod
    def list_top_reply_by_soft_article_id(cls, soft_article_id, offset, count, sort_condition=None):
        """帖子的一级评论"""
        if not sort_condition:
            sort_condition = '-id'

        replies = cls.model.objects.filter(
            softarticle_id=soft_article_id,
            top_id=cls.TOP_ID_NULL,
        )

        if isinstance(sort_condition, list) or isinstance(sort_condition, tuple):
            replies = replies.order_by(*sort_condition)
        else:
            replies = replies.order_by(sort_condition)

        replies = replies[offset: offset + count]

        result, target_info = [], []
        for item in replies:
            result.append({
                "id": item.id,
                "soft_article_id": item.softarticle_id,
                "replied_id": item.replied_id,
                "user_id": item.user_id,
                #"top_id": item.top_id, 暂时不传递
                "status": TRACTATE_REPLY_HIGHLIGHT.DARK,
                "reply_count": int(cls.top_reply_count(item.id) or 0),    #Todo一级评论评论数
                "is_vote": False,

                "content": item.content,
                "vote_num": item.vote_num,
                "create_time": item.create_time.timestamp(),
            })

        return result

    @classmethod
    def top_reply_count(cls, top_reply_id):
        """一级评论下的评论数"""
        reply_num = soft_article_reply_count.get(cls.reply_cache_key.format(top_id=top_reply_id))
        if not reply_num:
            return 0
        return reply_num

    @classmethod
    def update_reply_count(cls, top_reply_id):
        reply_num = soft_article_reply_count.incr(cls.reply_cache_key.format(top_id=top_reply_id))
        return reply_num

    @classmethod
    def set_reply_count(cls, top_reply_id, num):
        reply_num = soft_article_reply_count.set(cls.reply_cache_key.format(top_id=top_reply_id), num)
        return reply_num

    @classmethod
    def offline_reply(cls, reply_id):
        """下线评论"""
        reply = cls.get_by_id(reply_id)
        if not reply:
            return gen(ERROR.TRACTATEREPLY_NOT_FOUND)

        reply.is_online = False
        reply.save()

    @classmethod
    def create(cls, content, soft_article_id, merchant_id, user_id=None, doctor_id=None, extra={}):
        """创建评论。

        extra： 额外的参数。包括：top_id, replied_id, source_id
        """

        reply = cls.model()

        reply.content = content
        reply.user_id = user_id
        reply.doctor_id = doctor_id
        reply.merchant_id = merchant_id
        reply.top_id = extra.get("top_id") or cls.TOP_ID_NULL
        reply.softarticle_id = soft_article_id

        reply.source_id = extra.get("source_id", TRACTATE_PLATFORM.GM)
        reply.replied_id = extra.get("replied_id") or cls.REPIED_ID_NULL
        reply.is_fake = extra.get("is_fake", False)

        reply.save()
        return reply

    @classmethod
    def get_second_reply_by_top_id(cls, top_id, offset=0, count=10, sort_condition=None, target_reply_id=None):
        """获取一级评论下的二级评论"""
        if not sort_condition:
            sort_condition = '-id'

        top_replies = cls.model.objects.filter(top_id=top_id)

        if isinstance(sort_condition, list) or isinstance(sort_condition, tuple):
            top_replies = top_replies.order_by(*sort_condition)
        else:
            top_replies = top_replies.order_by(sort_condition)

        top_replies = top_replies[offset: offset + count]

        result = []
        for item in top_replies:
            temp_item = {
                "id": item.id,
                "soft_article_id": item.softarticle_id,
                "replied_id": item.replied_id,
                "user_id": item.user_id,
                "doctor_id": item.doctor_id,
                "top_id": item.top_id,
                "status": TRACTATE_REPLY_HIGHLIGHT.DARK,
                "is_vote": False,

                "content": item.content,
                "vote_num": item.vote_num,
                "create_time": item.create_time.timestamp(),
                "user_name": "",
                "user_portrait": "",
                "doctor_name": "",
                "doctor_portrait": "",
                "replied_user_id": "",
                "replied_user_name": "",
                "replied_user_portrait": "",
                "replied_doctor_id": "",
                "replied_doctor_name": "",
                "replied_doctor_portrait": "",
            }
            if target_reply_id and target_reply_id == item.id:
                temp_item['status'] = TRACTATE_REPLY_HIGHLIGHT.LIGHT
            result.append(temp_item)

        return result

    @classmethod
    def get_highlight_reply(cls, target_reply_id):
        target_reply_info = cls.get_by_id(pk=target_reply_id)
        if not target_reply_info:
            return gen(ERROR.TRACTATEREPLY_NOT_FOUND)

        if target_reply_info.top_id:
            top_reply_info = cls.get_by_id(pk=target_reply_info.top_id)
            if not top_reply_info:
                return gen(ERROR.TRACTATEREPLY_NOT_FOUND)
        else:
            top_reply_info = target_reply_info

        top_info = {
            "id": top_reply_info.id,
            "soft_article_id": top_reply_info.softarticle_id,
            "replied_id": top_reply_info.replied_id,
            "user_id": top_reply_info.user_id,
            # "top_id": top_reply_info.top_id,
            "status": TRACTATE_REPLY_HIGHLIGHT.LIGHT if target_reply_id == top_reply_info.id else TRACTATE_REPLY_HIGHLIGHT.DARK,
            "reply_count": cls.top_reply_count(top_reply_info.id),
            "is_vote": False,

            "content": top_reply_info.content,
            "vote_num": top_reply_info.vote_num,
            "create_time": top_reply_info.create_time.timestamp(),
            "replies": [],
        }

        return top_info

    @classmethod
    def offline_by_top_id(cls, top_id):
        """通过top_id下线评论"""
        effected_num = cls.model.objects.filter(top_id=top_id).update(is_online=False)
        return effected_num

    @classmethod
    def offline_by_reply_ids(cls, reply_ids):
        """通过id批量下线评论"""
        if not reply_ids:
            return 0
        effected_num = cls.model.objects.filter(id__in=reply_ids).update(is_online=False)
        return effected_num

    @classmethod
    def get_sub_reply_ids(cls, reply_id):
        reply_ids = cls.model.objects.filter(replied_id=reply_id, is_online=True).values_list('id', flat=True)
        sub_reply_ids = []
        sub_reply_ids.extend(reply_ids)
        for reply_id in reply_ids:
            sub_reply_ids.extend(cls.get_sub_reply_ids(reply_id))
        return sub_reply_ids


    @classmethod
    def offline_by_replied_id(cls, replied_id):
        """通过replied_id批量下线评论"""
        sub_reply_id_list = cls.get_sub_reply_ids(replied_id)
        effected_num = cls.offline_by_reply_ids(sub_reply_id_list)
        return effected_num

    @classmethod
    def get_replys(cls, softarticle_id, last_id, size):
        """
        获取一级评论和次级评论，一级评论按照时间先后排序，次级评论紧跟一级评论
        :return:
        """
        replys = list()
        top_replys = list(cls.model.objects.filter(
            softarticle_id=softarticle_id,
            top_id=0,
            is_online=True,
            id__gt=last_id
        )[0: size])

        # 依次查一级评论下二级评论，总数够size则返回
        for top_reply in top_replys:
            replys.append(top_reply)
            if len(replys) == size:
                break

            # 查询当前一级评论的次级评论
            sub_replys = list(cls.model.objects.filter(
                softarticle_id=softarticle_id,
                top_id=top_reply.id,
                is_online=True,
            )[0: size - len(replys)])

            replys.extend(sub_replys)

            if len(replys) == size:
                break

        return replys
