# coding=utf-8

import datetime
import logging
import re

from django.db.models import Q
from gm_types.gaia import DIARY_OPERATION
from gm_types.gaia import PROBLEM_FLAG_CHOICES, PRIVATE_STATUS, TOPIC_TYPE, FILTER_WORD_TYPE
from gm_types.push import PUSH_INFO_TYPE, PERSONAL_PUSH_TYPE, AUTOMATED_PUSH
from gm_types.user_hierarchy import EventType
from talos.tools.user_tool import get_username_with_title

# TODO xuepengfei 这个怎么处理?????
from talos.backbone.rpc import gen, CODES, logging_exception, get_rpc_remote_invoker
from talos.libs.reply import is_reply_num_gt_limit
from talos.models.topic import TopicReply
from talos.models.topic import TopicScore
from talos.services import DoctorService
from talos.tools.diary_rank_tool import DiaryRankTool
from talos.libs.protocol import gmdoctor_protocol, gm_protocol
from talos.tools.push_tool import limit_push
from mimas.tasks import send_event_task


def update_topic_score(user_id, topic, score):
    topic_score, created = TopicScore.objects.get_or_create(topic=topic, user_id=user_id)
    topic_score.score = score
    topic_score.save()
    return topic_score.id


def topic_reply_common(user, topic_id, reply_id=None, content='', device_id=None, is_fake=False):
    # todo 已迁移至mimas 仅供hera用，等待hera迁移  180502
    from talos.models.topic import Problem
    # TODO: user
    """话题回复.
        :param content: 回复的内容,
        :param reply_id: 评论ID，可选. 回复帖子时, 该字段为None; 回复其他评论时, 不可为空
        :param topic_id: 话题ID, 必选
        :param user: 用户
    """
    result = {
        'comment_data': {},
        'reply_data': {},
        'topic': {},
        'doctor': {},  # if user is a doctor, add doctor.id
    }

    # check if content is empty
    if not content.strip():
        return gen(CODES.REPLY_CAN_NOT_BE_EMPTY)

    # 检查用户在一分钟内回复(日记本/帖子)是否大于3条
    if is_reply_num_gt_limit(user=user):
        return gen(CODES.COMMENT_BUSY)

    replied_reply = None
    if reply_id:
        replied_reply = TopicReply.objects.filter(id=reply_id).first()
    # get right topic
    if replied_reply and replied_reply.problem:
        topic = replied_reply.problem
    else:
        try:
            topic = Problem.objects.get(id=topic_id)
        except Problem.DoesNotExist:
            topic = None

    if not topic:
        return gen(CODES.TOPIC_NOT_FOUND)

    result['topic']['id'] = topic.id
    result['topic']['ask'] = topic.ask
    result['topic']['topic_type'] = topic.topic_type
    result['topic']['tags'] = topic.get_tags()

    doctors = DoctorService.get_doctor_from_user_ids(user_ids=[user.id])
    doctor = doctors[0] if doctors else None

    if not (topic.flag == PROBLEM_FLAG_CHOICES.NORMAL or topic.is_online):
        return gen(CODES.TOPIC_HAS_BEEN_DELETED)

    # check if content contains forbiden words
    filter_word_list = get_rpc_remote_invoker()['talos/filterWord/list'](
        filter_type=FILTER_WORD_TYPE.TOPIC_REPLY
    )
    content = content if content else ""
    filter_word_list = filter_word_list.unwrap()
    if re.findall(u"\d{7,}", content) or any(word in content for word in filter_word_list):
        return gen(CODES.REPLY_CAN_NOT_CONTAIN_CONTACT)

    # check if content is same as the previous reply
    try:
        reply = TopicReply.objects.filter(problem=topic, user_id=user.id)
        last_id = reply.latest('id')
        previous_reply = TopicReply.objects.get(id=last_id.id)
        if previous_reply.content == content:
            return gen(CODES.REPLY_CAN_NOT_BE_REPEATED)
    except TopicReply.DoesNotExist:
        pass
    d = topic.diary
    if d is not None:
        if d.user_id == user.id:
            if reply_id:
                d = DiaryRankTool(d.id)
                t = datetime.datetime.now()
                replied_user_id = replied_reply.user.id
                d.add_heat(DIARY_OPERATION.SELF_REPLY, t, extra_id=replied_user_id)
        elif device_id:
            d = DiaryRankTool(d.id)
            t = datetime.datetime.now()
            d.add_heat(DIARY_OPERATION.OTHER_REPLY, t, extra_id=device_id)

    topic.reply_num += 1
    if topic.user_id == user.id:
        topic.author_reply_num += 1

    if doctor:
        result['doctor']['id'] = doctor.id

        # 限制民营医院医生
        if topic.private_status == PRIVATE_STATUS.NORMAL:
            reply_filter = Q(doctor_id=doctor.id) & Q(
                problem__private_status=PRIVATE_STATUS.NORMAL)
            today_reply_amount = TopicReply.objects.filter(reply_filter).extra(
                where=['date(reply_date)=CURRENT_DATE']
            ).count()

            if today_reply_amount >= doctor.reply_limit:
                return gen(CODES.DOCTOR_REPLY_TOPIC_LIMITED)

        get_rpc_remote_invoker()['doctor/update_last_answered_time'](doctor_id=doctor.id).unwrap()

        # 如果是医生的回复，就把该问题标记成已经回答
        topic.has_answer = True

        # TODO 一个医生回答多次只记录一次
        if topic.private_status == PRIVATE_STATUS.ASSIGN_DOCTOR_PRIVATE:
            topic.private_status = PRIVATE_STATUS.ASSIGN_DOCTOR_PRIVATE_ANSWERED

        elif topic.private_status == PRIVATE_STATUS.ASSIGN_DOCTOR:
            topic.private_status = PRIVATE_STATUS.ASSIGN_DOCTOR_ANSWERED

        topic.doctor_num += 1
        topic.save()

        doctor_today_reply_amount = TopicReply.objects.filter(
            doctor_id=doctor.id,
            reply_date__gt=datetime.date.today()
        ).count()
        result['doctor']['today_reply_count'] = doctor_today_reply_amount

    if not topic.is_topic and not topic.answer:
        topic.answer = content
        topic.assigned_doctor_id = user.id  # TODO: check
        topic.has_answer = True
        topic.reply_num = 1
        topic.doctor_num = 1
        topic.save()

    commented_reply = None
    if replied_reply:
        if replied_reply.commented_reply:
            commented_reply = replied_reply.commented_reply
        else:
            commented_reply = replied_reply

    topic_reply = TopicReply()
    topic_reply.problem = topic
    topic_reply.user_id = user.id
    topic_reply.doctor_id = doctor.id if doctor else None
    topic_reply.content = content
    topic_reply.replied_topic = replied_reply
    topic_reply.commented_reply = commented_reply
    topic_reply.is_fake = is_fake
    topic_reply.save()

    if topic.diary:
        from api.tool.caches import take_sofa_cache
        take_sofa_cache.del_diary_cache_data(topic.diary_id)

    if doctor:
        update_topic_score(doctor.user_id, topic, 0)

    elif replied_reply:
        try:
            is_doctor = DoctorService.get_doctor_by_user_id(user_id=replied_reply.user_id)
            is_doctor = bool(is_doctor)
        except IndexError:
            is_doctor = False
        if is_doctor:
            update_topic_score(replied_reply.user_id, topic, 3)

    topic.last_modified = datetime.datetime.now()
    topic.save()

    logging.info("create new reply, topic id is: {}, reply id is: {}".format(
        topic.id, topic_reply.id))

    # push
    try:
        if len(content) > 50:
            content = content[:50] + u'...'
        reply_username = get_username_with_title(user.id)
        msg = u'%s 回复你：%s' % (reply_username, content)

        receive_msg_user_ids = []

        if replied_reply:
            if user.id != replied_reply.user_id:
                receive_msg_user_ids.append(replied_reply.user_id)
        else:
            if user.id != topic.user_id:
                receive_msg_user_ids.append(topic.user_id)

        platform = ['android', 'iPhone']
        push_url = gm_protocol.get_comment_detail(id=reply_id, topic_id=topic_id)

        for receive_msg_user_id in set(receive_msg_user_ids):
            extra = {
                'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                'msgType': 4,
                'pushUrl': push_url,
                'push_url': push_url,
            }
            rpc_invoker = get_rpc_remote_invoker()
            alert = u'{user_name} 评论了你：{content} '\
                    .format(user_name=reply_username, content=content if len(content) <= 50 else content[50] + '...')
            try:
                rpc_invoker['push2/push/user/automated_push/uids'](
                    user_ids=[receive_msg_user_id],
                    platform=platform,
                    alert=alert,
                    extra=extra,
                    push_type=AUTOMATED_PUSH.DIARY_POST_RECEIVED_COMMENTS,
                ).unwrap()
            except:
                logging_exception()

            # if receiver is a doctor, push to doctor client
            try:
                recv_doctor = DoctorService.get_doctor_by_user_id(user_id=receive_msg_user_id)
            except IndexError:
                recv_doctor = None
            if recv_doctor:
                extra = {
                    'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                    'pushUrl': gmdoctor_protocol.get_comment_list(),
                }
                get_rpc_remote_invoker()['push2/push/doctor/notification/doctor_ids'](
                    doctor_ids=[recv_doctor.id],
                    platform=platform,
                    extra=extra,
                    alert=msg,
                ).unwrap()

    except:
        logging_exception()

    # 返回本身的数据
    try:
        reply_data = topic_reply.reply_data_after_create()
    except:
        reply_data = {}
        logging_exception()

    try:
        comment_data = topic_reply.comment_data_after_create()
    except:
        logging_exception()
        comment_data = {}

    # 新加评论时，2h随机加赞2-4
    # 产品需求, 将这段逻辑删除, 暂时保留防止有用
    """
    try:
        repeat_times, countdown = get_async_args(
            const_strings.TOPIC_REPLY_FAKE_VOTE)
        fake_vote.apply_async(args=(repeat_times, topic), countdown=countdown)
    except:
        logging_exception()
    """
    # add point, growth
    growth_value, point_value, submit_count = 0, 0, 0
    # if len(set(word for word in content)) > 5:
    if not replied_reply and user.id != topic.user_id \
            and topic.topic_type in [TOPIC_TYPE.ASK, TOPIC_TYPE.SHARE, TOPIC_TYPE.COLUMN_ARTICLE]:

        event_data = send_event_task(user_id=user.id, event_type=EventType.COMMENT_OTHER, related_item=topic_reply.id)
        growth_value, point_value, submit_count = event_data['growth_value'], event_data['point_value'], event_data[
            'submit_count']

    result['comment_data'] = comment_data
    result['reply_data'] = reply_data
    result['point_value'] = point_value
    result['growth_value'] = growth_value
    result['submit_count'] = submit_count
    return result
