from django.db.models import Q
from django.utils import timezone

from gm_types.error import ERROR

from utils.rpc import gen
from talos.services import UserService
from .base import BaseService

from talos.models.tractate import TractateVote, TractateReplyVote, Tractate


class TractateVoteService(BaseService):

    model = TractateVote

    @classmethod
    def set_read_by_user_id(cls, user_id):
        tractate_ids = list(Tractate.objects.filter(is_online=True, user_id=user_id).values_list('id', flat=True))

        cls.model.objects.filter(tractate_id__in=tractate_ids, is_read=False).update(
            is_read=True
        )

    @classmethod
    def create(cls, user_id, tractate):
        """创建点赞。"""

        author_id = tractate.user_id

        tv, created = cls.model.objects.get_or_create(
            tractate_id=tractate.id,
            user_id=user_id,
        )
        filter_bool = True if created or not tv.is_online else False
        if not tv.is_online:
            tv.is_online = True
            tv.is_read = False
            tv.save()

        return tv, filter_bool

    @classmethod
    def cancel(cls, tractate, user_id):
        """
        新帖子取消点赞
        :return:
        """
        tractate_id = tractate.id
        try:
            tv = cls.model.objects.get(user_id=user_id, tractate_id=tractate_id)
        except TractateVote.DoesNotExist:
            return gen(ERROR.TRACTATE_UNVOTE_ERROR)

        cancel_status = True if tv.is_online else False
        if cancel_status:
            tv.is_online = False
            tv.is_read = True
            tv.save()

        return tv, cancel_status

    @classmethod
    def unread_count(cls, tractate_id):
        """
        点赞未读数
        :return:
        """
        count = cls.model.objects.filter(tractate_id=tractate_id, is_read=False).count()
        return count

    @classmethod
    def get_tractate_voted_info_for_user(cls, tractate_ids, user_id):
        """
        获取用户对帖子已点赞的数据
        :param tractate_ids:
        :param user_id:
        :return:
        """
        result = dict()
        if not tractate_ids or not user_id:
            return result

        tvs = list(cls.model.objects.filter(
            tractate_id__in=tractate_ids,
            user_id=user_id,
            is_online=True
        ).values_list("tractate_id", flat=True))
        if not tvs:
            return result

        result = {tv: True for tv in tvs}
        return result


class TractateReplyVoteService(BaseService):

    model = TractateReplyVote

    @classmethod
    def set_read_by_user_id(cls, user_id):

        tractate_ids = list(Tractate.objects.filter(is_online=True, user_id=user_id).values_list('id', flat=True))

        cls.model.objects.filter(tractate_id__in=tractate_ids, is_read=False).update(
            is_read=True
        )

    @classmethod
    def create(cls, user_id, reply):
        """创建点赞。"""
        try:
            trv = cls.model.objects.get(user_id=user_id, tractate_id=reply.tractate_id, reply_id=reply.id)
        except TractateReplyVote.DoesNotExist:
            trv = cls.model.objects.create(user_id=user_id, tractate_id=reply.tractate_id, reply_id=reply.id)

        if not trv.is_online:
            trv.is_online = True
            trv.save()

        reply_author = UserService.get_user_by_user_id(user_id=reply.user_id)
        reply_author.incr_vote_count()

        return reply, trv

    @classmethod
    def cancel(cls, user_id, reply):
        """
        帖子回复取消点赞
        :param reply:
        :param user_id:
        :return:
        """

        cls.model.objects.filter(user_id=user_id, reply_id=reply.id).update(
            is_online=False, update_time=timezone.now())

        author = UserService.get_user_by_user_id(reply.user_id)
        author.decr_vote_count()

    @classmethod
    def unread_count(cls, tractate_id):
        """
        回复点赞未读数
        :param tractate_id:
        :return:
        """
        count = cls.model.objects.filter(tractate_id=tractate_id, is_read=False).count()
        return count

    @classmethod
    def get_vote_status(cls, user_id, tractate_id, reply_ids):
        if not user_id:
            return []
        base_query = Q(user_id=user_id, reply_id__in=reply_ids, is_online=True, )
        if tractate_id:
            base_query = base_query & Q(tractate_id=tractate_id)

        replied_ids = cls.model.objects.filter(tractate_id=tractate_id, user_id=user_id,
                                               reply_id__in=reply_ids, is_online=True)\
                                       .values_list('reply_id', flat=True)

        return list(replied_ids)
