# coding=utf8

from __future__ import unicode_literals, absolute_import, print_function

from django.conf import settings
from django.db import models
from django.db.models import Q
from django.utils import timezone
from django.utils.html import escape
from gm_types.gaia import DOCTOR_TYPE
from gm_types.gaia import PROBLEM_FLAG_CHOICES
from gm_types.gaia import TOPIC_TYPE
from gm_types.gaia import USER_TYPE
from gm_types.mimas import TRACTATE_SORT_TYPE
from gm_upload import IMG_TYPE
from gm_upload import ImgUrlField

from talos.libs.datetime_utils import get_humanize_datetime
from talos.libs.datetime_utils import get_timestamp
from talos.libs.datetime_utils import get_timestamp_or_none
from talos.models.diary.diary import Diary
from talos.models.topic.topic import Problem
from talos.rpc import CODES
from talos.rpc import gen
from talos.rpc import logging_exception
from talos.services.doctor import DoctorService
from talos.services.hospital import HospitalService
from talos.services.user import UserService


class TopicReply(models.Model):
    """
        回复的内容
    """

    class Meta:
        verbose_name = u'011.话题回复'
        verbose_name_plural = u'011. 话题回复'
        db_table = 'api_topicreply'
        app_label = 'talos'

    diary = models.ForeignKey(Diary, verbose_name=u"关联的日记本", null=True, blank=True, default=None)
    problem = models.ForeignKey(Problem, verbose_name=u"话题", null=True, blank=True, default=None)
    user_id = models.IntegerField(verbose_name=u'用户外键id')
    doctor_id = models.CharField(max_length=100, null=True, blank=True, verbose_name=u'医生外键id')
    hospital_id = models.CharField(max_length=100, null=True, blank=True, verbose_name=u'关联的医院外键id')

    replied_topic = models.ForeignKey("self", default=None, null=True, blank=True, verbose_name=u"被回复的信息")
    commented_reply = models.ForeignKey('self', related_name=u'comments', verbose_name=u'被评论的回复', null=True,
                                        blank=True, default=None)
    content = models.TextField(verbose_name=u"回复内容")
    image = ImgUrlField(img_type=IMG_TYPE.TOPICREPLY, max_length=100, default="", verbose_name=u"图片", null=True,
                        blank=True)
    audio = models.TextField(default="", verbose_name=u"音频", null=True, blank=True)
    is_new = models.BooleanField(default=True, verbose_name=u"是否新的回复", db_index=True)
    is_spam = models.BooleanField(verbose_name=u'是否为疑似广告', default=False, db_index=True)

    like_num = models.IntegerField(default=0, verbose_name=u"赞的数目")
    dislike_num = models.IntegerField(default=0, verbose_name=u"踩的数目")

    # FIXME: reply_date重命名成reply_time，避免混淆含义
    reply_date = models.DateTimeField(verbose_name=u"回复时间", db_index=True, default=timezone.now)
    is_topic_append = models.BooleanField(verbose_name=u'是否是更新', default=False, db_index=True)
    is_online = models.BooleanField(default=True, help_text=u"是否可以上线", verbose_name=u"上线")
    is_fake = models.BooleanField(default=False, verbose_name=u"是否是灌水数据")

    def is_voted(self, user, reply):
        # TODO CR
        from .topicreplyvote import TopicReplyVote
        """
        NOTE:
            对一级评论进行点赞
        """
        is_voted = TopicReplyVote.objects.filter(user_id=user.id, topic_reply=reply).exists() if user else False
        return is_voted

    def get_reply_info(self):
        data = {
            'id': self.id,
            'uid': self.user_id,
            'nickname': self.user.nickname,
            'content': escape(self.content),
            'reply_time': get_timestamp_or_none(self.reply_date),
            'images': [],
            'is_online': self.is_online,
            'can_reply': not self.replied_topic,
        }

        return data

    def get_reply_info_for_doctor(self):
        data = {
            'topic_id': self.problem.id,
            'reply_date': get_timestamp_or_none(self.reply_date),
            'like_num': self.like_num,
            'my_content': escape(self.content),
            "old_content": self.replied_topic.content if self.replied_topic_id else (
                self.problem.ask or self.problem.answer)
        }

        return data

    def __unicode__(self):
        return self.content

    def reply_data_after_create(self):
        if self.user_id:
            portrait = self.user.portrait
        else:
            portrait = u''

        user_type = USER_TYPE.NORMAL
        user_id = self.user_id
        if self.doctor_id:
            d = DoctorService.get_doctor_from_doctor_id(self.doctor_id)

            if d.doctor_type == DOCTOR_TYPE.OFFICER:
                user_type = USER_TYPE.OFFICER
                user_id = d.hospital_id
            elif d.doctor_type == DOCTOR_TYPE.DOCTOR:
                user_type = USER_TYPE.EXPERT
                user_id = self.doctor_id

        reply_data = {
            'reply_id': self.id,
            'user_type': user_type,
            'user_id': user_id,
            'user_nickname': escape(self.user.nickname) or u'昵称未设置',
            'user_portrait': portrait,
            'content': escape(self.content),
            'reply_date': get_humanize_datetime(self.reply_date),
            'reply_timestamp': get_timestamp(self.reply_date),
            'comments': [],
            'reply_count': self.comments.count(),
            'vote_count': self.like_num,
        }
        return reply_data

    def comment_data_after_create(self):
        if self.replied_topic and self.replied_topic.user_id == self.user_id:
            at_nickname = u''
        elif self.replied_topic:
            at_nickname = self.replied_topic.user.nickname
        else:
            at_nickname = u''

        user_type = 0
        if self.doctor_id:
            d = DoctorService.get_doctor_from_doctor_id(self.doctor_id)

            if d.doctor_type == DOCTOR_TYPE.OFFICER:
                user_type = 2
            elif d.doctor_type == DOCTOR_TYPE.DOCTOR:
                user_type = 1

        data = {
            'comment_id': self.id,
            'nickname': escape(self.user.nickname) or u'昵称未设置',
            'reply_id': self.replied_topic and self.replied_topic.id or '',
            'at_nickname': escape(at_nickname),
            'at_user_id': self.replied_topic.user_id if self.replied_topic else 0,
            'at_user_type': user_type,
            'comment_user_id': self.user_id,
            'comment_user_type': '',
            'content': escape(self.content),
            'reply_count': self.comments.count(),
            'vote_count': self.like_num,
        }
        return data

    def is_elite(self):
        """
        判断是否是热门回复
        """
        return self.like_num >= settings.ELITE_LIKE_NUM and True or False

    def get_reply_detail(self, user_id=None):
        from .replyheadline import ReplyHeadline    # 避免循环引用

        if self.user_id:
            city_name = self.user.city_name
            portrait = self.user.portrait
        else:
            city_name = u''
            portrait = u''

        user_type = 0
        doctor_info = UserService.get_doctor_from_user_id(self.user_id)
        if doctor_info is not None and doctor_info.is_online:
            doctor = doctor_info
            if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                user_type = USER_TYPE.OFFICER
                hospital_id = doctor_info.hospital_id
            else:
                user_type = USER_TYPE.EXPERT
                hospital_id = None
        else:
            doctor = None
            hospital_id = None

        hospital = HospitalService.get_hospital_from_doctor_id(self.doctor_id)
        if hospital is not None:
            hospital_name_full = hospital.name or u''
        else:
            hospital_name_full = u''
        hospital_name = hospital_name_full[:14] if len(hospital_name_full) <= 14 else hospital_name_full[:14] + '...'

        reply_data = {
            'user': {
                'user_id': self.user_id,
                'user_name': self.user.nickname,
                'is_doctor': True if doctor else False,
                'is_hospital': True if hospital_id is not None else False,
                'doctor_id': doctor.id if doctor else '',
                'doctor_name': doctor and doctor.name,
                'hospital_id': hospital_id if hospital_id is not None else '',
                'portrait': portrait,
                'user_type': user_type,
                'membership_level': self.user.membership_level,
            },
            'is_private': bool(user_id) and user_id == self.user_id,
            'doctor_portrait': DoctorService.get_doctor_from_doctor_id(self.doctor_id).portrait if self.doctor_id else '',
            'hospital_name': hospital_name,

            'is_recommend_doctor': False,
            'recommend_doctor_title': '',

            'favored': False,
            'images': [],
            'is_star_user': False,
            'city': city_name,
            'is_topic_append': self.is_topic_append,
            'reply': {
                'reply_id': self.id,
                'content': escape(self.content),
                'favor_amount': self.like_num,
                'reply_time': get_timestamp_or_none(self.reply_date),
                'is_voted': bool(user_id) and self.topicreplyvote_set.filter(user_id=user_id, topic_reply=self).exists(),
                'image': self.image,
                'is_new': self.is_new,
                'replied_topic_id': self.replied_topic and self.replied_topic.id or '',
                'reply_date': get_timestamp_or_none(self.reply_date),
                'commented_reply_id': (
                    self.replied_topic and self.commented_reply and
                    self.commented_reply.id or ''
                ),
                'like_num': self.like_num,
                'is_best_reply': self.is_best_reply(),
                'is_recommand': ReplyHeadline.is_recommend(self.id),    # TODO CR 修改这个函数
                'is_elite': self.is_elite(),
                'comments_num': self.comments.count(),
            }
        }
        try:
            reply_data['diary'], reply_data['topic'], reply_data['answer'] = None, None, None
            if self.problem:
                topic_info = self.get_reply_topic_info()
                reply_data['topic'] = topic_info

            if self.diary:
                diary_info = self.get_reply_diary_info()
                reply_data['diary'] = diary_info

            author_id = self.problem and self.problem.user_id or self.diary.user_id
            if self.user_id == author_id:
                reply_data['user_titles'] = [{'title_type': 0, 'title_text': u'楼主'}, ]
            else:
                reply_data['user_titles'] = []

            if self.is_topic_append:
                # 增加术后第几天的展示
                if self.problem.operation_time:
                    interval = self.reply_date.date() - self.problem.operation_time
                    if interval.days >= 0:
                        reply_data['interval'] = u'{}'.format(interval.days + 1)
                    else:
                        reply_data['interval'] = u'以前'
                else:
                    reply_data['interval'] = u''
        except:
            logging_exception()

        return reply_data

    def get_reply_topic_info(self):
        """
        NOTE:
            获取回复相关的帖子topic信息
        :return:
        """
        topic_info = {
            'id': self.problem_id,
            'title': (
                self.replied_topic and self.replied_topic.id and
                escape(self.replied_topic.content) or escape(self.problem.answer)
            ),
            'problem_ask': escape(self.problem.ask),
            'problem_answer': escape(self.problem.answer),
            'is_deleted': (
                self.problem.flag == PROBLEM_FLAG_CHOICES.MARK_DELETED or
                not self.problem.is_online
            ),
            'user': {
                'id': self.problem.user_id,
                'nickname': self.replied_topic and self.replied_topic.user.nickname or self.user.nickname
            },
        }
        if self.problem.topic_type == TOPIC_TYPE.WEIXIN_NUM:
            topic_info['title'] = self.problem.get_title()
        return topic_info

    def get_reply_diary_info(self):
        """
        NOTE:
            获取回复相关的日记本信息
            其中 显示的title做特殊处理
            title = 'tag'+'日记'
        :return:
        """
        title = escape(self.diary.title)

        tags_new_era = self.diary.tags_new_era
        if tags_new_era:
            title = tags_new_era[0]['name'] + u'日记'

        diary_info = {
            'id': self.diary.id,
            'title': title,
            'is_deleted': not self.diary.is_online,
            'user': {
                'id': self.diary.user_id,
                'nickname': UserService.get_user_by_user_id(self.diary.user_id).nickname,
            },
        }

        return diary_info

    def comment_data(self):
        if self.replied_topic:
            if self.replied_topic.user_id == self.user_id:
                at_nickname = u''
                at_doctor = None
                at_hospital_id = None
            else:
                if self.replied_topic.user_id is not None:
                    replied_doctor_info = UserService.get_doctor_from_user_id(self.replied_topic.user_id)
                    at_doctor = replied_doctor_info
                    if at_doctor and at_doctor.is_online and at_doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                        at_hospital_id = at_doctor.hospital_id
                    else:
                        at_hospital_id = None
                else:
                    at_doctor = None
                    at_hospital_id = None

                if self.replied_topic.doctor_id:
                    u = UserService.get_user_id_by_doctor_id(self.replied_topic.doctor_id)
                    at_nickname = u and UserService.get_user_by_user_id(u).nickname or u'昵称未设置'
                else:
                    at_nickname = self.replied_topic.user.nickname or u'昵称未设置'
        else:
            at_nickname = u'昵称未设置'
            at_doctor = None
            at_hospital_id = None

        if self.user_id:
            portrait = self.user.portrait
        else:
            portrait = u''

        doctor_info = UserService.get_doctor_from_user_id(self.user_id)
        if doctor_info is not None and doctor_info.is_online:
            doctor = doctor_info
            if doctor.doctor_type == DOCTOR_TYPE.OFFICER:
                hospital_id = doctor.hospital_id
            else:
                hospital_id = None
        else:
            doctor = None
            hospital_id = None

        data = {
            'type': 0,
            'content': escape(self.content),
            'at_nickname': at_nickname,
            'at_doctor_id': at_doctor.id if at_doctor else '',
            'at_hospital_id': at_hospital_id if at_hospital_id is not None else '',
            'user_portrait': portrait,
            'at_user_id': self.replied_topic.user_id if self.replied_topic else '',
            'nickname': '',
            'comment_id': self.id,
            'comment_time': self.reply_date.strftime('%m.%d'),
            'comment_expert_id': doctor.id if doctor else '',
            'at_expert_id': at_doctor.id if at_doctor else '',
            'user_id': self.user_id,
            'user_is_doctor': True if doctor else False,
            'user_is_hospital': True if hospital_id is not None else False,
            'doctor_id': doctor.id if doctor else '',
            'hospital_id': hospital_id if hospital_id is not None else '',
            'membership_level': self.user.membership_level,
            'is_best_reply': self.is_best_reply(),
        }

        if self.doctor_id is not None:
            d = DoctorService.get_doctor_from_doctor_id(self.doctor_id)
            data['nickname'] = d.name
            if d.user != settings.SUOZHANG_UID:
                data['nickname'] += u' 医生'
        else:
            data['nickname'] = self.user.nickname or u'昵称未设置'

        return data

    @classmethod
    def get_by_id(cls, id):
        try:
            return TopicReply.objects.get(pk=id)
        except:
            return None

    def is_best_reply(self):
        """
            是否是优质问答
        """
        return self.replyheadline_set.filter(is_online=True).exists()

    def update_reply_num(self, is_online=False):
        real_replynum = 1 + TopicReply.objects.filter(commented_reply=self).count()
        if self.problem:
            if is_online:
                self.problem.reply_num += real_replynum
                self.problem.update_reply_num(is_online=True, reply_num=real_replynum)
            else:
                self.problem.reply_num -= real_replynum
                self.problem.update_reply_num(is_online=False, reply_num=real_replynum)

            if self.problem.reply_num < 0:
                return False
            self.problem.save()

        elif self.diary:
            if is_online:
                self.diary.reply_num += real_replynum
            else:
                self.diary.reply_num -= real_replynum

            if self.diary.reply_num < 0:
                return False
            self.diary.save()

        return True

    @classmethod
    def get_replies_info(cls, user, replies, start_num=0, count=10, comment_id=None, new_sub_comment_count=False,
                         is_xcx=False):
        from talos.manager import comment_data_by_reply_ids, get_reply_details_by_reply_ids
        result = []
        need_add_reply_id = None
        if comment_id:
            top_comment = TopicReply.objects.filter(id=comment_id, commented_reply_id__isnull=True).first()
            replies = list(replies)
            if not top_comment:
                reply = TopicReply.objects.get(id=comment_id)
                replies = [item for item in replies if item.id != reply.commented_reply.id]
                replies = [reply.commented_reply] + replies
                if is_xcx and start_num == 0:
                    need_add_reply_id = reply.commented_reply_id
            else:
                replies = [item for item in replies if item.id != top_comment.id]
                replies = [top_comment] + replies
        _replies = replies[start_num: start_num + count]
        reply_ids = [r.id for r in _replies]
        comments_ids = list(TopicReply.objects.filter(Q(commented_reply__id__in=reply_ids) &
                                                      Q(is_online=True))
                            .values_list('id', flat=True))
        comments_data = comment_data_by_reply_ids(comments_ids)
        topicreplys_data = get_reply_details_by_reply_ids(reply_ids, user.id)
        for reply in _replies:
            replies_data = None
            for _reply in topicreplys_data:
                if _reply['reply']['reply_id'] == reply.id:
                    replies_data = _reply
                    break
            if replies_data is None:
                continue

            reply_info = replies_data['reply']
            if reply.replyheadline_set.count() == 0:
                replies_data['reply']['is_recommand'] = False
            else:
                replies_data['reply']['is_recommand'] = True

            replies_data['reply']['is_elite'] = (1 if reply_info['favor_amount'] >= settings.ELITE_LIKE_NUM else 0)

            replies_data['comments'] = []

            if new_sub_comment_count:
                _reply_comments_ids = list(reply.comments.filter(
                    is_online=True
                ).order_by('-id').values_list('id', flat=True))[:2]  # 取最新两条
            else:
                _reply_comments_ids = list(reply.comments.filter(
                    is_online=True
                ).values_list('id', flat=True))

            second_top_comment = None
            for c in comments_data:
                if c['comment_id'] in _reply_comments_ids:
                    replies_data['comments'].append(c)

                if comment_id and not second_top_comment and c['comment_id'] == int(comment_id):
                    second_top_comment = c

            # 将二级评论 置顶
            if need_add_reply_id and need_add_reply_id == reply.id and second_top_comment:
                replies_data['comments'] = [item for item in replies_data['comments']
                                            if item['comment_id'] != int(comment_id)]
                replies_data['comments'].insert(0, second_top_comment)

            result.append(replies_data)
        return result

    @classmethod
    def get_replies_list_info(
            cls, user, query, start_num=0, count=10, comment_id=None, new_sub_comment_count=False
    ):
        """
        NOTE:
            首先获取热门评论数目
            如果不够，则继续获取最新评论
            获取 日记本 帖子 评论列表信息
        :param user:
        :param start_num:
        :param count:
        :param new_sub_comment_count: 子评论展示个数控制， 7130 以及评论下展示两个子评论
        :return:
        """
        recommand_reply = Q(like_num__gte=settings.ELITE_LIKE_NUM)
        recommand_reply &= query
        replies = TopicReply.objects.filter(recommand_reply)
        hot_count = replies.count()
        if comment_id:
            myreplies = TopicReply.objects.filter(id=comment_id)
            replies = myreplies | replies

        result = []
        if hot_count > start_num:
            replies = replies.order_by('-like_num', '-reply_date')
            result = cls.get_replies_info(
                user, replies, start_num=start_num, count=count,
                comment_id=comment_id, new_sub_comment_count=new_sub_comment_count
            )

        if len(result) < count:
            if start_num < hot_count:
                start_num = 0
            else:
                start_num = start_num - len(result) - hot_count

            count -= len(result)
            last_query = Q(like_num__lt=settings.ELITE_LIKE_NUM)
            last_query &= query
            last_replies = cls.objects.filter(last_query).order_by('-id').exclude(recommand_reply)
            last_result = cls.get_replies_info(
                user, last_replies,
                start_num=start_num,
                count=count,
                comment_id=comment_id,
                new_sub_comment_count=new_sub_comment_count,
            )
            result.extend(last_result)

        return result

    @classmethod
    def reply_detail_diary(cls, user, reply_id, start_num=0, count=10):
        from talos.manager.topic_reply import comment_data_by_reply_ids

        try:
            reply = TopicReply.objects.get(pk=reply_id)
        except TopicReply.DoesNotExist:
            return gen(CODES.TOPIC_NOT_FOUND)
        topic = reply.problem

        result = {
            'comments': [],
            'topic_id': topic.id,
            'title': topic.diary.title,
            'comment_count': topic.topicreply_set.count(),
            'reply_id': reply.id,
            'is_private': False if not user else user.id == reply.user_id,
            'doctor_id': '',
            'doctor_portrait': '',
            'doctor_name': '',
            'hospital_name': '',
            'is_recommend_doctor': False,
            'recommend_doctor_title': '',
            'favored': False,
            'favor_amount': topic.vote_amount,
            'content': topic.answer,
            'images': [i.get_image_data() for i in topic.images.all()],
            'user_id': reply.user_id,
            'user_nickname': reply.user.nickname,
            'user_portrait': reply.user.portrait,
            'is_star_user': False,
            'reply_date': get_timestamp_or_none(topic.created_time),
            'city': reply.user.city_name,
            'is_topic_append': True,
        }

        doctor_reply_sql = """
            (case when api_topicreply.doctor_id !='' then 1 else 0 end)
        """
        comments = topic.topicreply_set.extra(
            select={'doctor_reply': doctor_reply_sql})
        comments = comments.extra(order_by=['-doctor_reply', 'id'])
        comments = comments[start_num: start_num + count]
        _comments_ids = [c.id for c in comments]
        result['comments'] = comment_data_by_reply_ids(_comments_ids)

        return result

    @property
    def user(self):
        if hasattr(self, '_user_obj'):
            return self._user_obj

        self._user_obj = UserService.get_user_by_user_id(self.user_id)
        return self._user_obj

    @property
    def doctor(self):
        return DoctorService.get_doctor_from_doctor_id(self.doctor_id)

    @property
    def hospital(self):
        return HospitalService.get_hospital_from_hospital_id(self.hospital_id)

    def get_reply_for_mine(self):
        return {
            'reply': {
                'replied_topic_id': self.replied_topic_id or '',
                'content': escape(self.content),
                'reply_id': self.id,
                'commented_reply_id': self.replied_topic_id and self.commented_reply_id or '',
                'reply_date': get_timestamp_or_none(self.reply_date),
                'image': self.image,
                'is_new': self.is_new,
                'commented_content': self.replied_topic.content if self.replied_topic else None,
                'commented_user_id': self.replied_topic.user_id if self.replied_topic else None,
            },
            'user': {
                'doctor_name': '',
                'user_name': '',
                'doctor_id': '',
                'user_id': self.user_id,
                'user_portrait': '',
                'doctor_portrait': '',
            },
            'topic': {
                'user': {
                    'nickname': '',
                    'id': self.problem.user_id,
                    'portrait': '',
                },
                'id': self.problem_id,
                'problem_ask': escape(self.problem.ask),
                'title': self.replied_topic_id and escape(self.replied_topic.content) or escape(self.problem.answer),
                'is_deleted': self.problem.flag == PROBLEM_FLAG_CHOICES.MARK_DELETED or not self.problem.is_online,
            } if self.problem_id else None,
            'diary': {
                'user': {
                    'nickname': '',
                    'id': self.diary.user_id,
                    'portrait': '',
                },
                'id': self.diary_id,
                'title': escape(self.diary.title),
                'is_deleted': not self.diary.is_online,
            } if self.diary_id else None,
            'answer': None,
        }
