# coding=utf8

from __future__ import unicode_literals, absolute_import, print_function

from django.conf import settings
from django.db.models import Q
from django.utils.html import escape
from gm_rpcd.all import bind
from gm_types.error import ERROR as CODES
from gm_types.gaia import MY_COMMENT_TYPE
from gm_types.gaia import PROBLEM_FLAG_CHOICES, NotificationType
from talos.models.topic import ReplyHeadline
from talos.models.topic import Problem

from talos.decorators import list_interface
from talos.libs.datetime_utils import get_timestamp_or_none
from talos.manager.topic_reply import (
    comment_data_by_reply_ids,
    get_my_replies,
    get_diary_replies,
    get_reply_details_by_reply_ids,
    get_my_replies_count_from_mysql
)
from talos.models.reply import ReplyCollect
from talos.models.topic.topicreply import TopicReply
from talos.models.topic import Problem
from talos.rpc import bind_context
from talos.services import get_user_from_context, DoctorService, UserService
from talos.tools.reply_tool import topic_reply_common, get_topic_reply # TODO CR 这边需要重构 和重构的时候一起拆
from talos.cache.reply import reply_cache
from utils.rpc import gen, rpc_client, get_current_user, logging_exception


@bind_context("topic/topic_reply")
# @bind_context("talos/topic/reply")
@list_interface(offset_name='start_num', limit_name='count',
                element_model=TopicReply,
                element_func_list=[TopicReply.get_reply_detail])
def get_reply_info(
        ctx, id=None, only_doctor_reply=False, count=10, start_num=0, comment_id=None,
        new_sub_comment_count=False
):
    """话题评论详情
       id:话题ID
       only_doctor_reply:只返回医生回复，默认False
    """
    user = get_user_from_context(ctx)
    topic = Problem.get_by_id(id)
    if topic:
        if topic.flag == PROBLEM_FLAG_CHOICES.NORMAL and topic.is_online:
            replies = get_topic_reply(start_num=start_num,
                                      count=count,
                                      user=user,
                                      topic_obj=topic,
                                      only_doctor_reply=only_doctor_reply,
                                      comment_id=comment_id,
                                      new_sub_comment_count=new_sub_comment_count
                                      )
            if new_sub_comment_count:
                return replies
            return replies.get("topic_replies", [])
        else:
            return gen(CODES.TOPIC_HAS_BEEN_DELETED)
    else:
        return gen(CODES.TOPIC_NOT_FOUND)


@bind_context('topic/reply/sub_comment')
def get_topic_reply_by_reply_id(ctx, reply_id, topic_id=None, start_num=0, count=10):
    """
    获取评论的子评论
    :param ctx:
    :param reply_id:
    :param topic_id:
    :param start_num:
    :param count:
    :return:
    """
    result = {
        'replies': []
    }
    if not reply_id:
        return result

    replies = []
    if reply_id:
        replies = TopicReply.objects.filter(
            commented_reply_id=reply_id, is_online=True
        ).order_by('-id')

    if not replies:
        return result

    _replies = replies[start_num: start_num + count]
    reply_ids = [r.id for r in _replies]
    comments_data = comment_data_by_reply_ids(reply_ids)

    return {
        'replies': comments_data
    }


@bind("topic/topic_reply_create")
# @bind_context("talos/reply/create")
def topic_reply_create(topic_id, reply_id=None, content='', device_id=None, platform_channel=None):
    """话题回复.
        :param ctx:
        :param content: 回复的内容,
        :param reply_id: 评论ID，可选. 回复帖子时, 该字段为None; 回复其他评论时, 不可为空
        :param topic_id: 话题ID, 必选
        :param user: 用户
    """
    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)
    # TODO CR topic_reply_common 这个先缓一缓...
    return topic_reply_common(user, topic_id, reply_id, content, device_id, platform_channel)


@bind_context('topic/total_reply_num')
def get_total_reply_num(ctx, topic_id=None):
    total_reply_num = TopicReply.objects.filter(problem=topic_id, is_online=True).count()
    return {
        'total_reply_num': total_reply_num
    }


@bind("topic/replies_my")
# @bind_context("talos/reply/my_list")
@list_interface(offset_name='start_num', limit_name='count', element_model=TopicReply,
                element_func_list=[TopicReply.get_reply_detail])
def get_replies_mine(start_num=0, count=10, send_or_receive=MY_COMMENT_TYPE.RECEIVED, with_comment=True):
    """received sent comments.

    args:
        send_or_receive: 0 as received, 1 as sent
    """
    try:
        user = get_current_user()
        if not user:
            return gen(CODES.LOGIN_REQUIRED)
        result = []
        reply_user_ids = []
        un_read_reply_ids, replies = get_my_replies(user.id, send_or_receive, start_num, count)

        for reply in replies:
            try:
                result.append(reply.get_reply_for_mine())
                reply_user_ids.append(reply.user_id)
            except AttributeError:
                result.append(reply)
                reply_user_ids.append(reply['user']['user_id'])
        reply_users = UserService.get_users_by_user_ids(reply_user_ids)
        _reply_doctors = DoctorService.get_doctor_from_user_ids(reply_user_ids)
        reply_doctors = {d.user_id: d for d in _reply_doctors}
        reply_topic_user_ids = [r.problem.user_id if hasattr(r, 'problem') and r.problem else None for r in replies]
        reply_diary_user_ids = [r.diary.user_id if hasattr(r, 'diary') and r.diary else None for r in replies]
        reply_answer_user_ids = [r.answer.user_id if hasattr(r, 'answer') and r.answer else None for r in replies]
        commented_answer_user_ids = [r.get('reply')['commented_author_id']
                                     if isinstance(r, dict) and r.get('reply') and r.get('reply').get('commented_author_id')
                                     else None for r in replies]
        commented_topic_user_ids = [r.commented_reply.user_id
                                    if hasattr(r, 'problem') and r.problem and r.commented_reply
                                    else None for r in replies]
        user_ids = reply_diary_user_ids + reply_topic_user_ids + reply_answer_user_ids + \
                   commented_answer_user_ids + commented_topic_user_ids
        users = UserService.get_users_by_user_ids(user_ids)

        current_user = {
            'nick_name': user.nick_name,
            'portrait': user.portrait,
        }

        for r in result:
            uid = r['user']['user_id']
            if uid in reply_users:
                r['user']['user_name'] = reply_users[uid].nickname
                r['user']['user_portrait'] = reply_users[uid].portrait
            if uid in reply_doctors:
                doctor = reply_doctors[uid]
                if not doctor.is_online:
                    r['user']['doctor_id'] = doctor.id
                    r['user']['doctor_name'] = doctor.name
                    r['user']['doctor_portrait'] = doctor.portrait
            if r['diary']:
                duid = r['diary']['user']['id']
                if duid in users:
                    r['diary']['user']['nickname'] = users[duid].nickname
                    r['diary']['user']['portrait'] = users[duid].portrait

            if r['topic']:
                tuid = r['commented_reply']['user_id'] if hasattr(r, 'reply') and r['reply'] and\
                                                        r['reply']['commented_user_id']\
                                                        else r['topic']['user']['id']
                if tuid in users:
                    r['topic']['user']['nickname'] = users[tuid].nickname
                    r['topic']['user']['portrait'] = users[tuid].portrait
                    r['topic']['title'] = r['reply']['commented_content'] if r['reply']['commented_content'] \
                                                                          else r['topic']['title']
            if r.get('answer', ''):
                auid = r['reply']['commented_author_id'] \
                        if r.get('reply').get('commented_author_id') \
                        else r['answer']['user']['id']
                if auid in users:
                    r['answer']['user']['nickname'] = users[auid].nickname
                    r['answer']['user']['portrait'] = users[auid].portrait
                    r['answer']['title'] = r['reply']['commented_content'] \
                                           if r['reply'].get('commented_content') \
                                           else r['answer']['title']

            r.update({'current_user': current_user})
        # 将所有回复设置为已读
        # tips: answer reply 在获取reply data时update  is_read=true
        TopicReply.objects.filter(id__in=un_read_reply_ids, is_new=True).update(is_new=False)

        return result

    except Problem.DoesNotExist:
        pass

    return None


@bind("topic/replies/receive")
def get_my_topic_replies_receive(replies_ids):
    """获取我收到的日记帖评论。"""

    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    user_ids = []
    topic_ids = []

    topic_replies_dict = get_diary_replies(replies_ids)
    for _, reply in topic_replies_dict.items():
        # reply.commented_reply 表示 被评论的回复，有则当前为二级评论
        topic_ids.append(reply.problem_id)
        user_ids.append(reply.user_id)  # 评论用户id

    topics = Problem.objects.filter(pk__in=topic_ids, is_online=True)
    for topic in topics:
        user_ids.append(topic.user_id)

    users_dict = UserService.get_users_by_user_ids(user_ids)

    doctors_dict = {}
    doctors = DoctorService.get_doctor_from_user_ids(user_ids)
    for doctor in doctors:
        doctors_dict[doctor.user_id] = doctor

    result = {}
    for reply_id, reply in topic_replies_dict.items():

        reply_user = users_dict.get(reply.user_id, {})
        doctor = doctors_dict.get(reply.user_id, {})

        doctor_info = {}
        if doctor:
            doctor_info = {
                "user_id": doctor.user_id,
                "doctor_id": doctor.id,
                "name": doctor.name,
            }

        diary_info = {}
        if reply.diary:
            diary_info = {
                "id": reply.diary_id,
                "title": reply.diary.title,
            }

        topic_info = {}
        if reply.problem:
            topic_info = {
                "id": reply.problem.id,
            }

        my_content = ''
        if reply.commented_reply:
            my_content = reply.commented_reply.content
        elif reply.problem:
            my_content = reply.problem.answer

        info = {
            "id": reply_id,
            "reply_id": reply_id,

            "diary": diary_info,
            "topic": topic_info,

            # "msg_type": "回复了我的问答",  #  backend拼装
            # "url": "gengmei://answer_detail?answer_id=531149&comment_id=152631" # backend拼装

            "is_deleted": False,
            "is_new": False,
            "reply_date": get_timestamp_or_none(reply.reply_date),
            "reply_content": reply.content,
            "my_content": my_content,

            "reply_user": {
                "name": reply_user.nickname,
                "portrait": reply_user.portrait,
            },
            "author": {
                "id": user.id,
                "name": user.nick_name,
                "portrait": user.portrait,
            },

            "doctor": doctor_info,
        }
        result[str(reply_id)] = info

    return result



@bind('topic/reply_info')
def get_topicreply_info(reply_id=None):
    """
    获取指定id的回复
    """
    try:
        reply = TopicReply.objects.get(pk=reply_id)
        user = UserService.get_user_by_user_id(reply.user_id)
        result = {
            'portrait': user.portrait,
            'nick_name': user.nickname,
            'reply_time': get_timestamp_or_none(reply.reply_date),
            'content': reply.content,
            'user_id': reply.user_id,
            'is_hot': reply.is_elite(),
            'membership_level': user.membership_level,
            'is_recommend': ReplyHeadline.is_recommend(reply_id),
            'doctor_id': '',
            'hospital_id': '',
        }

        user_bz = UserService.get_doctor_hospital_id_by_user_id(reply.user_id)
        if user_bz:
            result['user_id'] = user_bz['user_id']
            result['doctor_id'] = user_bz['doctor_id']
            result['hospital_id'] = user_bz['hospital_id']

        return result

    except TopicReply.DoesNotExist:
        return gen(CODES.TOPIC_REPLY_NOT_FOUND)


# @bind('talos/first/topic_reply/content')
# def trans_problem_answers(problem_id):
#     result = {}
#     reply = TopicReply.objects.filter(problem_id=problem_id)
#     if reply:
#         result['content'] = reply[0].content
#     return result


@bind('topic/topic_reply/get_reply_info_by_ids')
def topic_reply_info(ids):
    """
    :param ids: topic_reply_id list
    :return:
    [
        {
            'id': 1,
            'data': {
                'id': 2,
                'uid': 3,
                'content': str,
                'reply_time': xxx,
                'images': []
                'is_online': bool,
                'can_reply': bool
            }
        }
    ]
    """
    if len(ids) == 0:
        return []

    replies = TopicReply.objects.filter(id__in=ids)
    wanted_fields = [
        'id',
        'user_id',
        'content',
        'replied_topic_id',
        'is_online',
        'reply_date',
    ]
    data = replies.values(*wanted_fields)
    result = []
    for d in data:
        r = {
            'id': d['id'],
            'uid': d['user_id'],
            'content': escape(d['content']),
            'reply_time': get_timestamp_or_none(d['reply_date']),
            'images': [],
            'is_online': d['is_online'],
            'can_reply': not d['replied_topic_id'],
        }
        d = {
            'id': r['id'],
            'data': r,
        }
        result.append(d)
    return result


@bind('topic/topic_reply/update_reply_num_by_ids')
def update_reply_num(ids, is_online=False):
    """
    :param ids: topic_reply_id list
    is_online
    :return:
    [
        {
            'id': 1,
            'data': bool,
        }
    ]
    """
    if len(ids) == 0:
        return False

    replies = TopicReply.objects.filter(id__in=ids)
    result = []
    for reply in replies:
        r = reply.update_reply_num(is_online)
        d = {
            'id': reply.id,
            'data': r,
        }
        result.append(d)
    return result


@bind("topic/topic_reply/my_list_for_doctor")
@list_interface(offset_name='start_num', limit_name='count', element_model=TopicReply,
                element_func_list=[TopicReply.get_reply_detail])
def get_my_reply_lsit_for_dotor(
        start_num=0, count=10, send_or_receive=MY_COMMENT_TYPE.RECEIVED,
        with_comment=True, filter_topic=False):
    """received sent comments.

    args:
        send_or_receive: 0 as received, 1 as sent
        filter_topic:  只刷选帖子相关的评论
    """
    result = []
    try:
        user = get_current_user()
        if not user:
            return gen(CODES.LOGIN_REQUIRED)

        # TODO: @weijialiang
        if send_or_receive == MY_COMMENT_TYPE.RECEIVED:
            reply_ids = ReplyCollect.objects.filter(reply_user_id=user.id,
                                                    topic_reply_id__isnull=False).order_by('-created_time').values_list('topic_reply_id', flat=True)[start_num:start_num + count]
        elif send_or_receive == MY_COMMENT_TYPE.SENT:
            reply_ids = ReplyCollect.objects.filter(user_id=user.id,
                                                    topic_reply_id__isnull=False).order_by('-created_time').values_list('topic_reply_id', flat=True)[start_num:start_num + count]
        else:
            return gen(CODES.OPERATION_NOT_SUPPORTED)
        reply_ids = list(reply_ids)

        query = Q(id__in=reply_ids, is_online=True)
        if filter_topic:
            query &= Q(problem__isnull=False)
        replies = TopicReply.objects.filter(query).order_by('-id')

        if reply_ids:
            _reply_ids = list(replies.values_list('id', flat=True))
            topicreplys_data = get_reply_details_by_reply_ids(_reply_ids)
            comments_ids = []
            for r in replies:
                _comments_ids = list(r.comments.filter(is_online=True).values_list('id', flat=True))
                comments_ids += _comments_ids
            comments_data = comment_data_by_reply_ids(comments_ids)

            for reply in replies:
                for _reply in topicreplys_data:
                    if _reply['reply']['reply_id'] == reply.id:
                        replies_data = _reply
                        break
                    else:
                        continue
                if with_comment:
                    replies_data['comments'] = []
                    _reply_comments_ids = list(reply.comments.filter(is_online=True).values_list('id', flat=True))
                    for c in comments_data:
                        if c['comment_id'] in _reply_comments_ids:
                            replies_data['comments'].append(c)
                result.append(replies_data)

            # 将所有回复设置为已读
            TopicReply.objects.filter(
                id__in=reply_ids, is_new=True).update(is_new=False)

        return result

    except Problem.DoesNotExist:
        return None


@bind_context('topic/replies_my/reseived_aggregation')
def get_my_replies_count(ctx):
    No_new_msg = {
        'is_about_me': False,
        'toptitle': '',
        'type': NotificationType.REPLY_ME,
        'unread_count': 0,
        "title": u'回复',
        "url": "",
        "content": "",
        "create_time": "",
        "user": "",
        "is_view": False,
        "imgheader": settings.NOTIFICATION_REPLY_IMG,
        "pic": "",
        "id": '',
    }
    user = get_user_from_context(ctx)
    if not user:
        return No_new_msg

    info = get_my_replies_count_from_mysql(user.id)
    count = info["count"]
    last_user_id = info["last_user_id"]
    created_time = info["created_time"]
    if count == 0:
        return No_new_msg
    else:
        last_user_info = UserService.get_user_by_user_id(last_user_id)
        if last_user_id == user.id:
            return No_new_msg
        return {
            'is_about_me': False,
            'toptitle': '',
            'type': NotificationType.REPLY_ME,
            'unread_count': count,
            "title": u'{}等人回复你'.format(last_user_info.nickname) if count > 1 else u'{}回复了你'.format(last_user_info.nickname),
            "url": "",
            "content": "",
            "create_time": get_timestamp_or_none(created_time),
            "user": "",
            "is_view": False,
            "imgheader": last_user_info.portrait,
            "pic": "",
            "id": '',
        }


@bind_context('topic/replies_my/reseived_aggregation/v1')
def get_my_replies_count_v1(ctx):
    result = {
        "count": 0,
        "last_user_info": {},
        "create_time": 0,
    }
    user = get_user_from_context(ctx)
    if not user:
        return result

    info = get_my_replies_count_from_mysql(user.id)
    count = info["count"]
    last_user_id = info["last_user_id"]
    created_time = info["created_time"]
    if not count or not last_user_id:
        return result

    last_user_info = UserService.get_user_by_user_id(last_user_id)
    result["count"] = count
    result["created_time"] = get_timestamp_or_none(created_time),
    result["last_user_info"].update({
        "nickname": last_user_info.nickname,
        "portrait": last_user_info.portrait,
    })
    return result


@bind('topic/unread_comments/count')
def user_unreadcomments():
    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    reply_ids = reply_cache.get_received_comment_ids(user.id)
    if reply_ids:
        replies = TopicReply.objects.filter(id__in=reply_ids)
        replies = replies.filter(is_new=True)
        return replies.count()
    return 0


@bind('topic/read_reply')
def topic_read_reply():
    user = get_current_user()
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    replies = ReplyCollect.objects.filter(reply_user_id=user.id).exclude(
        answer_id__isnull=False, user_id=user.id).order_by('-id')
    topic_reply_pks = [collect.topic_reply_id for collect in replies if collect.topic_reply_id]

    TopicReply.objects.filter(id__in=topic_reply_pks, is_new=True).update(is_new=False)
