# coding=utf-8

import datetime
import logging
from django.db.models import Q
from gm_types.error import ERROR as CODES
from gm_types.gaia import DIARY_OPERATION, PLATFORM_CHANNEL, DOCTOR_PROCESS_STATUS
from gm_types.gaia import PROBLEM_FLAG_CHOICES, PRIVATE_STATUS, TOPIC_TYPE, FILTER_WORD_TYPE
from gm_types.mimas import TRACTATE_SORT_TYPE

from gm_types.user_hierarchy import EventType

from talos.tools.hospital_tool import HospitalTool
from ..models.topic import TopicScore, TopicReply, Problem
from talos.models.doctor import DoctorMessageList

from talos.libs.diaryrank_utils import DiaryRankTool
from talos.libs.reply import is_reply_num_gt_limit
from talos.services import DoctorService
from talos.tasks import push_diary_reply_message, applet_topic_replied_push, applet_topic_reply_summary_push
from talos.tools.filterword_tool import filterword_by_custom
from utils.rpc import gen, rpc_client, logging_exception
from user_hierarchy.portal import process_task
from utils.stat_log import SocialStatLogForUserAction


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, platform_channel=None):
    # from ..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)

    # check if user is not in one organize
    if topic.topic_type == TOPIC_TYPE.SHARE and not HospitalTool.in_one_hospital(topic, user.id):
        return gen(CODES.TOPIC_REPLY_BAN_NOT_OWN)

    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)

    #以前的代码进行了数字的过滤，本次沿用以前的逻辑
    filterword_by_custom(filter_type=FILTER_WORD_TYPE.TOPIC_REPLY, content=content)

    # 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 and replied_reply:
                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)

        rpc_client['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.save()

    # 给被评论的用户发小程序push
    applet_topic_replied_push.delay(topic_reply.id)

    # 24小时后，如果当前评论没有收到评论或点赞，则给当前评论用户发送相关小程序push
    applet_topic_reply_summary_push.apply_async((topic_reply.id,), countdown=86400)

    comment_reply_id = topic_reply.id if not reply_id else reply_id

    if doctor:
        DoctorMessageList.objects.filter(topic_id=topic.id, doctor_id=doctor.id,
                                         process_status=DOCTOR_PROCESS_STATUS.unprocessed).\
            update(process_status=DOCTOR_PROCESS_STATUS.processed)

    if topic.diary:
        from talos.cache.takesofacache 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.save()

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

    replied_reply_user_id = replied_reply.user_id if replied_reply else None
    topic_user_id = topic.user_id if topic else None
    push_diary_reply_message(user_id=user.id,
                             content=content,
                             reply_id=comment_reply_id,
                             topic_id=topic.id,
                             replied_reply_user_id=replied_reply_user_id,
                             topic_user_id=topic_user_id)

    # 返回本身的数据
    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()
    """

    # 用户行为埋点，评论相关
    _topic_type = topic.topic_type
    if _topic_type in [TOPIC_TYPE.ASK, TOPIC_TYPE.SHARE, TOPIC_TYPE.TOPIC]:  # 日记帖
        _stat_log_data = {
            "user_id": user.id,
            "content_id": topic.diary_id,
            "content_type": SocialStatLogForUserAction.CONTENT_TYPE.diary
        }

    elif _topic_type in [TOPIC_TYPE.USER_ARTICLE, TOPIC_TYPE.COLUMN_ARTICLE]:  # 专栏
        _stat_log_data = {
            "user_id": user.id,
            "content_id": topic.id,
            "content_type": SocialStatLogForUserAction.CONTENT_TYPE.article
        }

    else:
        _stat_log_data = {}

    if _stat_log_data:
        SocialStatLogForUserAction.stat_log_for_reply(**_stat_log_data)

    # 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 = rpc_client['mimas/user/process_event_task'](
        #     user_id=user.id, event_type=EventType.COMMENT_OTHER, related_item=topic_reply.id).unwrap()
        event_data = process_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


def get_xcx_topic_reply(start_num, count, user, topic, sort_type, comment_id):
    """
    获取日记帖的评论
    :param start_num:
    :param count:
    :param user:
    :param topic:
    :param sort_type:
    :return:
    """
    replies_list = []

    if topic and topic.is_online and topic.flag == PROBLEM_FLAG_CHOICES.NORMAL:
        query = Q(problem_id=topic.id, commented_reply_id__isnull=True, is_online=True)

        # 小程序获取最新评论
        if sort_type in [TRACTATE_SORT_TYPE.NEWEST]:
            replies = TopicReply.objects.filter(query).order_by('-id')
        else:
            # 默认获取最热
            replies = TopicReply.objects.filter(query).order_by('-like_num', 'id')

        replies_list = TopicReply.get_replies_info(
            user, replies, start_num=start_num, count=count, comment_id=comment_id, is_xcx=True
        )

    return replies_list

def get_topic_reply(
        start_num, count, user, topic_obj=None, topic_id=None,
        only_doctor_reply=False, is_new=False, comment_id=None,
        new_sub_comment_count=False
):
    """
    通过日记帖id or objects,获取该日记帖下的评论
    :param topic_obj: 日记帖对象
    :param topic_id:  日记帖id
    :param start_num: 评论起始数
    :param count: 个数
    :param only_doctor_reply: 仅要医生的回复
    :param is_new: 是否取最新评论
    :param new_sub_comment_count: 子评论展示个数
    :return: result dict
    """
    result = {
        "topic_replies": [],
    }
    if topic_id:  # 优先获取topic_id
        topic = Problem.get_by_id(topic_id)
    elif topic_obj:
        topic = topic_obj

    if topic and topic.is_online and topic.flag == PROBLEM_FLAG_CHOICES.NORMAL:
        query = Q(problem_id=topic.id, commented_reply_id__isnull=True, is_online=True)

        if only_doctor_reply:
            query = Q(doctor_id__isnull=False) & query
            replies = TopicReply.objects.filter(query)
            first_reply_count = replies.count()
            replies = replies[start_num: start_num + count]
            replies_list = TopicReply.get_replies_info(
                user, replies, start_num=start_num, count=count, comment_id=comment_id,
                new_sub_comment_count=new_sub_comment_count
            )
        else:
            replies = TopicReply.objects.filter(query).order_by("-id")
            first_reply_count = replies.count()
            if is_new:
                replies = replies[start_num: start_num + count]
                replies_list = TopicReply.get_replies_info(
                    user, replies, start_num=0, count=count, comment_id=comment_id,
                    new_sub_comment_count=new_sub_comment_count
                )
            else:
                replies_list = TopicReply.get_replies_list_info(
                    user, query, start_num=start_num, count=count,  comment_id=comment_id,
                    new_sub_comment_count=new_sub_comment_count
                )

        result['first_reply_count'] = first_reply_count
        result["topic_replies"] = replies_list

    return result
