# encoding=utf-8
from __future__ import unicode_literals

from datetime import datetime

from django.db import IntegrityError, transaction
from django.db.models import Q, Count
from django.conf import settings

from api.models import (PROBLEM_FLAG_CHOICES, Service, Order)
from api.models.types import PROBLEM_REVIEW_STATUS_CHOICES, CASH_BACK_STATUS, TAG_TYPE
from api.tasks.export_excel_task import export_diary_rank_top1000
from api.tool.datetime_tool import get_timestamp
from talos.tools.diary_tool import get_diary_by_id, push_diary_reply_message
from api.tool.image_utils import get_full_path, get_short_path
from talos.tools.topic_tool import get_topic_reply_by_id
from api.tool.user_tool import get_user_from_context
from api.tool.user_tool import get_user_by_id
from api.tool.filterword_tool import filterword_function
from gm_types.gaia import USER_CLASSIFY
from gm_types.gaia import DIARY_CONTENT_LEVEL, DIARY_AUDIT_STATUS, SERVICE_TYPE, INDEX_CARD_TYPE
# from hera.queries.talos.diary import DiaryDQ
from hera.viewmodels.diary.queries import DiaryDQ
from hera.queries.talos.diarycheck import DiarycheckDQ
from hera.views.user import user_create
from rpc.decorators import bind_context
from rpc.exceptions import RPCIntegrityError, RPCNotFoundException
from rpc.tool.dict_mixin import to_dict
from rpc.tool.error_code import CODES, gen
from rpc.tool.log_tool import info_logger
from rpc.tool.time_tool import get_current_time
from rpc.context import get_rpc_remote_invoker
from services.talos_service import (
    topic_reply_get_reply_info_by_ids, topic_reply_update_reply_num_by_ids,
    diary_num_and_cover_by_id, diary_num_and_cover_by_ids,
    diary_get_diary_info_by_ids, topic_get_tags_by_ids, topic_vote_amount_by_id,
    topic_vote_amount_by_ids, topic_update_reply_num_by_id,
    topic_update_reply_num_by_ids,
)
from talos.services.user import UserService
from mimas.event_manager import EventDispatcher
from talos.models.diary import (
    Diary, DiaryTag, DiaryMessage, DiaryCheck, DiaryRank, DiaryTagV3,
)
from talos.models.draft import Draft
from talos.models.diary.preoperationimage import PreOperationImage
from talos.models.topic import (Problem, TopicReply, TopicImage)
from talos.tools.topic_tool import modify_diary_video_tag_by_topic_ids
from services.talos_service import diary_update_doctor_messages_status
from api.tasks.doctor_rank_task import delete_diary_rank
from statistic.models import ClassifyUser
from gm_types.gaia import USER_CLASSIFY, FILTER_WORD_TYPE
from api.view.service import get_services_tag_name_by_service_ids
from talos.services import AntiSpamService

__author__ = 'leaf'

uri_pre = 'hera/diary'


def _get_topic_pageview(id):
    # return Problem.get_view_amount_of_id(id)
    return topic_vote_amount_by_id(id=id).get('view_amount')


@bind_context(uri_pre + '/get')
def diary_detail(ctx, diary_id, options=None):
    user = get_user_from_context(ctx)
    try:
        diary = Diary.objects.get(id=diary_id)
    except:
        raise RPCNotFoundException
    if options is None:
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
    diary_data = to_dict(diary, **options)
    diary_data['tags'] = [t.id for t in diary.all_tags]
    diary_data["tag_v3_ids"] = list(DiaryTagV3.objects.filter(diary_id=diary_id).values_list("tag_v3_id", flat=True))

    vote_view_cover = diary_num_and_cover_by_id(id=diary.id)
    diary_data['diary_amount'] = vote_view_cover.get('diary_amount')
    diary_data['vote_num'] = vote_view_cover.get('vote_num')
    diary_data['view_num'] = vote_view_cover.get('view_num')
    for image in vote_view_cover.get('cover'):
        if image['desc'] == 'Before':
            diary_data['pre_operation_image'] = image['image']
        else:
            diary_data['post_operation_image'] = image['image']
    diary_data['topics'] = []
    diary_data['pre_operation_images'] = []
    topic_filter = Q(flag=PROBLEM_FLAG_CHOICES.NORMAL)
    topics = diary.topics.filter(topic_filter).prefetch_related("images").annotate(
        reply_count=Count('topicreply')).order_by('-created_time')
    user = UserService.get_user_by_user_id(diary.user_id)
    user_nickname = user.nickname
    user_portrait = user.portrait
    membership_level = user.membership_level
    for topic in topics:
        interval = ''
        if diary.operation_time:
            interval = topic.created_time - diary.operation_time
            if interval.days >= 0:
                interval = interval.days + 1
            else:
                interval = ''

        topic_data = {
            'id': topic.id,
            'content': topic.answer,
            'interval': interval,
            'images': [get_full_path(i.image_url) for i in topic.images.all()],
            'created_time': get_timestamp(topic.created_time),
            'last_modified_time': get_timestamp(topic.last_modified),
            'reply_num': topic.reply_num,
            'doctor_num': topic.doctor_num,
            # 'vote_num': topic.vote_amount,   改从接口调用
            # 'view_num': _get_topic_pageview(topic.id),   改从接口调用
            'user_nickname': user_nickname,
            'user_portrait': user_portrait,
            'membership_level': membership_level,
            'is_online': topic.is_online,
            # 'tags': topic.get_tags(),  改从接口调用
            'can_video_cover': topic.can_video_cover,
            'is_voted': topic.votes.filter(user_id=user.id).exists() if user else False,
            'images_raw': [
                {
                    'image_url': get_full_path(i.image_url),
                    'taken_time': get_timestamp(i.taken_time),
                    'is_cover': i.is_cover
                }
                for i in topic.images.all()
                ],
            "remark": topic.remark,
        }
        if getattr(topic, 'video', None):
            topic_data['video'] = topic.video.get_video_info()
        diary_data['topics'].append(topic_data)

    topic_ids = [_topic_data['id'] for _topic_data in diary_data['topics']]
    id_tags = topic_get_tags_by_ids(ids=topic_ids)  # [{id:xxx,data:yyy},]
    id_vote_nums = topic_vote_amount_by_ids(ids=topic_ids)

    id_tag_dics = {}
    id_vote_num_dics = {}
    for topic_id in topic_ids:
        # initial all topic_ids
        id_tag_dics[topic_id] = []
        id_vote_num_dics[topic_id] = {'vote_amount': 0, 'view_amount': 0}
    for dic in id_tags:
        id_tag_dics.update({dic['id']: dic['data']})
    for dic in id_vote_nums:
        id_vote_num_dics.update({dic['id']: dic['data']})

    for _topic_data in diary_data['topics']:
        topic_id = _topic_data['id']
        _topic_data['tags'] = id_tag_dics[topic_id]
        _topic_data['vote_num'] = id_vote_num_dics[topic_id]['vote_amount']
        _topic_data['view_num'] = id_vote_num_dics[topic_id]['view_amount']

    diary_data['pre_operation_images'] = [
        {
            'image_url': get_full_path(pre_operation_image.image_url),
            'is_cover': pre_operation_image.is_cover
        }
        for pre_operation_image in diary.pre_operation_images.all()
        ]
    if ClassifyUser.objects.filter(user_id=diary.user_id, classify=USER_CLASSIFY.MODEL).exists():
        diary_data['is_real'] = u'否'
    else:
        diary_data['is_real'] = u'是'
    return diary_data


# @bind_context(uri_pre + '/list')
# def diary_datatable(ctx, req_data):
#     dtobj = DiaryDT(Diary)
#     return dtobj.process(req_data,
#                          ['doctor__name', 'hospital__name', 'service__name', 'user__last_name',
#                           'id', 'title'])


@bind_context(uri_pre + '/query')
def diary_query(ctx, options):
    dqobj = DiaryDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/choices')
def diary_choices(ctx, q='', page=1, num=30, initial=None, doctor_id=None, tag_id=None):
    page = int(page)
    num = int(num)

    if initial is not None:
        if isinstance(initial, (list, tuple)):
            qry = Q(id__in=initial)
        else:
            qry = Q(id=initial)
    else:
        qry = Q(id__contains=q) | Q(title__contains=q)

    if doctor_id is not None:
        if isinstance(doctor_id, (list, tuple)):
            qry &= Q(doctor_id__in=doctor_id)
        else:
            qry &= Q(doctor_id=doctor_id)

    if tag_id is not None:
        if isinstance(tag_id, (list, tuple)):
            diary_ids = DiaryTag.objects.filter(tag_id__in=tag_id).values_list('diary_id', flat=True)
        else:
            diary_ids = DiaryTag.objects.filter(tag_id=tag_id).values_list('diary_id', flat=True)
        qry &= Q(id__in=set(diary_ids))

    query = Diary.objects.using(settings.MIMAS_SLAVE_DB_NAME).filter(qry)
    # total_count = query.count()
    total_count = 0
    start_pos = (page - 1) * num
    start_pos = start_pos if start_pos >= 0 else 0
    results = [
        {
            'id': obj.id,
            'text': u'{}:{}'.format(obj.id, obj.title),
        } for obj in query[start_pos: start_pos + num]
        ]
    return {'total_count': total_count, 'results': results, 'page': page, 'num': num}


@bind_context(uri_pre + '/edit')
def diary_edit(ctx, diary_id=None, diary_info=None, urls=None):
    if diary_info is None:
        return None

    tags = diary_info.pop('tags', [])
    tag_v3_ids = diary_info.pop("tag_v3_ids", [])
    diary_info['user_id'] = diary_info.pop('user_id')
    diary_info['hospital_id'] = diary_info.pop('hospital_id') or None
    diary_info['service_id'] = diary_info.pop('service_id') or None
    diary_info['doctor_id'] = diary_info.pop('doctor_id') or None
    diary_info['order_id'] = diary_info.pop('order_id') or None
    diary_info.pop('operation_time')
    diary_info.pop('diary_amount')
    diary_info.pop('vote_num')
    diary_info.pop('view_num')
    diary_info.pop('last_topic_add_time')
    diary_info['last_modified'] = get_current_time("%Y-%m-%d %H:%M:%S")
    diary_info.pop('id')
    diary_info.pop('reply_num')
    diary_info.pop('is_real')
    if diary_info['order_id']:
        diary_info['service_id'] = Order.objects.get(id=diary_info['order_id']).service_id

    if diary_id is None:
        try:
            diary = Diary.objects.create(**diary_info)
        except IntegrityError:
            raise RPCIntegrityError
    else:
        try:
            diary = Diary.objects.get(id=diary_id)
        except:
            info_logger.info(__import__('traceback').format_exc())
            raise RPCNotFoundException
        if diary.hospital_id and diary_info['hospital_id'] != diary.hospital_id:
            from hippo.models import Hospital
            hos = Hospital.objects.get(id=diary.hospital_id)
            delete_diary_rank.delay(diary_ids=[diary.id], doctor_id=hos.officer.id)
        if diary.doctor_id and diary_info['doctor_id'] != diary.doctor_id:
            delete_diary_rank.delay(diary_ids=[diary.id], doctor_id=diary.doctor_id)
        if not diary_info['is_online']:
            delete_diary_rank.delay(diary_ids=[diary.id])

        diary_update_doctor_messages_status(ids=[diary.id], data_type=INDEX_CARD_TYPE.DIARY,
                                            status=diary_info['is_online'])
        for k, v in diary_info.iteritems():
            setattr(diary, k, v)
        diary.save()

    # tags特殊处理
    if tags:
        diary.upd_tags(tags)

    tag_v3_new_ids = set(map(int, tag_v3_ids))
    tag_v3_old_ids = set(DiaryTagV3.objects.filter(diary_id=diary_id).values_list("tag_v3_id", flat=True))

    DiaryTagV3.objects.filter(diary_id=diary_id, tag_v3_id__in=tag_v3_old_ids - tag_v3_new_ids).delete()
    for tag_id in (tag_v3_new_ids - tag_v3_old_ids):
        DiaryTagV3.objects.get_or_create(diary_id=diary_id, tag_v3_id=tag_id)

    pre_image = PreOperationImage.objects.filter(diary=diary)
    short_urls = []
    for url in urls:
        short_urls.append(get_short_path(url))
    if short_urls:
        for url in short_urls:
            preopimgs = PreOperationImage.objects.filter(diary=diary, image_url=url)
            if url and not preopimgs.exists():  # url为空则无操作
                PreOperationImage.objects.create(diary=diary, image_url=url)
        # 删除删除掉的条目
        to_delete = pre_image.filter(~Q(image_url__in=short_urls))
        if to_delete.filter(is_cover=True):
            diary.pre_operation_image = ''
            diary.save()
        to_delete.delete()
    prj_types = [TAG_TYPE.BODY_PART, TAG_TYPE.BODY_PART_SUB_ITEM, TAG_TYPE.ITEM_WIKI]
    prj_tags = diary.get_tags_from_tags_by_types(diary.all_tags, prj_types)
    return prj_tags[0].name if prj_tags else ''


@bind_context('hera/diary/set_cover')
def diary_set_cover(ctx, diary_id, image_url, position, cover_image_url, topic_id):
    """设置日记本封面， 用于新后台日记本封面设置
       diary_id: 做更新操作的日记本ID
       image_url: 封面图片url
       position: 设置为左|右封面
    """
    try:
        with transaction.atomic():
            diary = Diary.objects.get(pk=diary_id)
            image_url = get_short_path(image_url)
            cover_image_url = get_short_path(cover_image_url)
            if position == "left":
                diary.pre_operation_image = cover_image_url
                diary.pre_operation_images.update(is_cover=False)
                cover = diary.pre_operation_images.get(image_url=image_url)
            else:
                diary.post_operation_image = cover_image_url
                topic_images = TopicImage.objects.filter(topic_id=topic_id)
                topic_images.update(is_cover=False)
                cover = topic_images.get(image_url=image_url)
            cover.is_cover = True
            cover.cover_image_url = cover_image_url
            cover.save()
            diary.save()

            try:
                get_rpc_remote_invoker()['diary/cache_cover_by_ids_or_topic_ids'](diary_ids=[diary.id]).unwrap()
            except:
                pass
            return {"message": "success"}
    except Diary.DoesNotExist:
        return None


@bind_context(uri_pre + '/topic_online')
def topic_online(ctx, is_online='', topic_ids=None):
    """
    topic在线状态更新
    topic_ids: 话题ID, 必选
    is_online: 下线
    """
    online_ids = []
    not_online_ids = []
    for topic_id in topic_ids:
        topic = Problem.objects.get(pk=topic_id)
        if topic:
            # 日记贴上下线
            if topic.is_online != is_online:
                # topic.update_reply_num(is_online)
                if is_online:
                    online_ids.append(topic_id)
                else:
                    not_online_ids.append(topic_id)
            topic.is_online = is_online
            topic.save()
    modify_diary_video_tag_by_topic_ids(topic_ids)
    topic_update_reply_num_by_ids(ids=online_ids, is_online=True)
    topic_update_reply_num_by_ids(ids=not_online_ids, is_online=False)

    diary_update_doctor_messages_status(ids=not_online_ids, data_type=INDEX_CARD_TYPE.DIARY_TOPIC)
    diary_update_doctor_messages_status(ids=online_ids, data_type=INDEX_CARD_TYPE.DIARY_TOPIC, status=True)
    try:
        get_rpc_remote_invoker()['diary/cache_cover_by_ids_or_topic_ids'](topic_ids=topic_ids).unwrap()
    except:
        pass

    return topic.id


@bind_context(uri_pre + '/topic_content')
def topic_content_edit(ctx, content='', topic_id=None):
    """
    topic在线状态更新
    topic_ids: 话题ID, 必选
    is_online: 下线
    """
    topic = Problem.objects.get(pk=topic_id)
    if topic:
        topic.answer = content
        topic.save()
    return topic.id


@bind_context(uri_pre + '/excel')
def diary_list(ctx, ids=None):
    if ids:
        filter_query = Q(id__in=ids)
    diaries = Diary.objects.filter(filter_query)
    diaries = diaries.distinct()
    diary_list = []
    total = diaries.count()

    # for diary in diaries:
    #     diary_data = diary.get_diary_info(simple=True)
    #     # diary_data['view_num'] = diary.view_num
    #     diary_data['view_num'] = diary_num_and_cover(id=diary.id).get('view_num')
    #     diary_list.append(diary_data)

    diary_ids = [diary.id for diary in diaries]
    diary_datas = diary_get_diary_info_by_ids(ids=diary_ids, simple=True)
    diary_data_view_nums = diary_num_and_cover_by_ids(ids=diary_ids)
    for diary_data in diary_datas:
        for dic in diary_data_view_nums:
            if dic['id'] == diary_data['diary_id']:
                diary_data['view_num'] = dic['data'].get('view_num')
                break
        diary_list.append(diary_data)

    result = {'diaries': diary_list,
              'total': total}
    return result


@bind_context(uri_pre + '/topics')
def get_diary_topics(ctx, diary_id):
    try:
        diary = Diary.objects.get(id=diary_id)
    except:
        raise RPCNotFoundException

    q = ~Q(review_status=PROBLEM_REVIEW_STATUS_CHOICES.OK) & Q(is_online=True)
    topics = diary.topics.filter(q).prefetch_related("images").order_by('id')
    data = []
    for topic in topics:
        # 程序自动审一遍图片数量和字数
        images = [get_full_path(item.image_url) for item in topic.images.all()]
        # topic.set_review_status(len(images))    #刷新时不再更新帖子状态
        topic.save()
        # content_limit = False
        # if len(images) < settings.CASHBACK_TOPIC_IMAGE_LIMIT:
        #     content_limit = True
        # elif len(topic.answer) < settings.CASHBACK_TOPIC_CONTENT_WORDS_LIMIT:
        #     content_limit = True
        #
        # if content_limit:
        #     try:
        #         topic.review_status = PROBLEM_REVIEW_STATUS_CHOICES.CONTENT_LIMIT
        #         topic.save()
        #     except:
        #         pass
        if topic.review_status != PROBLEM_REVIEW_STATUS_CHOICES.NOT_REVIEW:
            continue
        topic_data = {
            'id': topic.id,
            'title': topic.ask,
            'content': topic.answer,
            'created_time': get_timestamp(topic.created_time),
            'last_modified': get_timestamp(topic.last_modified),
            'reply_num': topic.topicreply_set.count(),
            # 'vote_num': topic.vote_amount,   改从接口调用
            'is_online': topic.is_online,
            'images': images,
            'review_status': topic.review_status
        }
        if getattr(topic, 'video', None):
            topic_data['video'] = topic.video.get_video_info()
        data.append(topic_data)
    diary_ids = [_topic_data['id'] for _topic_data in data]
    id_vote_nums = topic_vote_amount_by_ids(ids=diary_ids)
    id_vote_num_dics = {}
    for dic in id_vote_nums:
        id_vote_num_dics.update({dic['id']: dic['data']})
    for _topic_data in data:
        _topic_data['vote_num'] = id_vote_num_dics[_topic_data['id']]['vote_amount']
    return data


@bind_context(uri_pre + '/update_topic')
def update_topic_status(ctx, topic_id, is_online, review_status):
    try:
        topic = Problem.objects.get(id=topic_id)
    except Problem.DoesNotExist:
        return gen(CODES.TOPIC_NOT_FOUND)
    # 日记贴上下线
    if topic.is_online != is_online:
        # topic.update_reply_num(is_online)
        topic_update_reply_num_by_id(id=topic.id, is_online=is_online)
    topic.is_online = is_online
    topic.review_status = review_status
    topic.save()
    try:
        topic.diary.order.cashback.set_topic_cash_back_num()
    except:
        pass

    diary_update_doctor_messages_status(ids=[topic_id], data_type=INDEX_CARD_TYPE.DIARY_TOPIC, status=is_online)

    return topic.id


@bind_context(uri_pre + '/can_cash_back')
def can_cash_back(ctx, diary_id):
    """
    日记本是否达到返现标准
    """
    try:
        diary = Diary.objects.get(id=diary_id)
    except Diary.DoesNotExist:
        return gen(CODES.DIARY_NOT_FOUND)

    if not diary.order:
        return gen(CODES.ORDER_NOT_FOUND)

    order = diary.order
    if order.cash_back_status == CASH_BACK_STATUS.SUCCESS:
        return gen(CODES.ALREADY_CASH_BACK)

    data = {
        'can_cash_back': False,
        'order': {
            'id': order.id,
            'payment_channel': order.payment_channel
        }
    }

    has_comments = diary.comment or diary.rating > 0
    if not has_comments:
        return data

    if order.cash_back_fee:
        cash_back = order.cash_back_fee
    else:
        return data

    topic_num_threshold = int(cash_back / 50) + 1
    total_valid_topics = diary.topics.filter(review_status=PROBLEM_REVIEW_STATUS_CHOICES.OK, is_online=True).count()
    if total_valid_topics >= topic_num_threshold:
        data['can_cash_back'] = True

    return data


@bind_context(uri_pre + '/listupdate')
def diary_listupdate(ctx, items):
    info = [obj['key'] for obj in items]
    Diary.objects.filter(id__in=info).update(is_online=obj['is_online'])
    Draft.objects.filter(diary_id__in=info).update(is_show=obj['is_online'])
    if not obj['is_online']:
        delete_diary_rank.delay(diary_ids=info)
    diary_update_doctor_messages_status(ids=info, data_type=INDEX_CARD_TYPE.DIARY,
                                        status=obj['is_online'])
    return info


@bind_context(uri_pre + '/sinkupdate')
def diary_sinkupdate(ctx, items):
    info = [obj['key'] for obj in items]
    Diary.objects.filter(id__in=info).update(is_sink=True)
    return info


@bind_context(uri_pre + '/unsinkupdate')
def diary_unsink(ctx, items):
    info = [obj['key'] for obj in items]
    Diary.objects.filter(id__in=info).update(is_sink=False)
    return info


@bind_context(uri_pre + '/add_reply')
def diary_add_reply(ctx, user_id, content, diary_id=None, reply_id=None):
    if not user_id or not content:
        return None

    replied_reply = None
    if reply_id:
        replied_reply = get_topic_reply_by_id(reply_id)

    if replied_reply and replied_reply.diary:
        diary = replied_reply.diary
    else:
        diary = get_diary_by_id(diary_id)

    # 查看最近用户有没有回复内容一样的留言
    try:
        reply = TopicReply.objects.filter(diary=diary, 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

    commented_reply = (
        replied_reply.commented_reply if replied_reply and replied_reply.commented_reply else replied_reply)

    user = get_user_by_id(user_id)
    topic_reply = TopicReply()
    topic_reply.diary = diary
    topic_reply.user_id = user_id
    topic_reply.content = content
    topic_reply.replied_topic = replied_reply
    topic_reply.commented_reply = commented_reply
    topic_reply.save()

    # 日记本评论数修改
    if diary:
        diary.reply_num += 1
        diary.save()

    # push 异步消息通知
    # replied_reply 被回复的TopicReply对象
    push_diary_reply_message(user, diary, content, replied_reply)

    return topic_reply.id


@bind_context(uri_pre + '/reply_list')
def diary_reply_list(ctx, diary_id):
    # topic_replies = TopicReply.objects.filter(diary_id=diary_id)
    # reply_list = []
    # for item in topic_replies:
    #     reply_list.append(item.get_reply_info())
    topic_replie_ids_dic = TopicReply.objects.filter(diary_id=diary_id).values('id')
    topic_replie_ids = [v for dic in topic_replie_ids_dic for k, v in dic.items()]
    reply_list = topic_reply_get_reply_info_by_ids(ids=topic_replie_ids)
    return reply_list


@bind_context(uri_pre + '/update_reply_online_status')
def update_reply_online_status(ctx, diary_reply_ids, is_online):
    online_ids = []
    not_online_ids = []
    ids = []
    for id in diary_reply_ids:
        try:
            topic_reply = TopicReply.objects.get(id=id)
            if topic_reply.is_online != is_online:
                # topic_reply.update_reply_num(is_online=is_online)
                if is_online:
                    online_ids.append(topic_reply.id)
                else:
                    not_online_ids.append(topic_reply.id)
            topic_reply.is_online = is_online
            topic_reply.save()
            ids.append(id)
        except:
            pass
    topic_reply_update_reply_num_by_ids(ids=online_ids, is_online=True)
    topic_reply_update_reply_num_by_ids(ids=not_online_ids, is_online=False)
    return ids


@bind_context(uri_pre + '/update_reply_content')
def update_reply_content(ctx, diary_reply_id, content):
    try:
        topic_reply = TopicReply.objects.get(id=diary_reply_id)
    except TopicReply.DoesNotExist:
        raise RPCNotFoundException

    topic_reply.content = content
    topic_reply.save()
    return topic_reply.id


@bind_context(uri_pre + '/delete_reply')
def delete_reply(ctx, diary_reply_id):
    try:
        topic_reply = TopicReply.objects.get(id=diary_reply_id)
    except TopicReply.DoesNotExist:
        raise RPCNotFoundException

    topic_reply.delete()


@bind_context(uri_pre + '/get_from_ids')
def diary_get_from_ids(ctx, ids):
    diary_data = []
    diarys = Diary.objects.filter(id__in=ids)
    for diary in diarys:
        data = {
            'id': diary.id,
            'title': diary.title,
        }
        diary_data.append(data)

    return diary_data


@bind_context(uri_pre + '/get_diarymessage')
def get_diarymessage(ctx):
    """
    获取预设话述列表
    """
    result = {}
    for key, value in DIARY_CONTENT_LEVEL:
        messages = DiaryMessage.objects.filter(is_delete=False, level=key)
        result[key] = [{'id': item.id,
                        'description': item.description,
                        'title': item.title,
                        'value': item.message} for item in messages]
    return result


@bind_context(uri_pre + '/delete_message')
def delete_message(ctx, id):
    """
    删除预设话述
    """
    message = DiaryMessage.objects.get(pk=id)
    message.is_delete = True
    message.save()


@bind_context(uri_pre + '/add_message')
def add_message(ctx, level, message, title, description):
    """
    添加预设话述
    """
    data = DiaryMessage.objects.create(level=level, message=message, title=title, description=description)
    diarymessage_data = {
        'id': data.id,
        'message': data.message,
        'description': data.description,
        'level': data.level,
        'title': data.title
    }
    return diarymessage_data


@bind_context(uri_pre + '/check/query')
def diarycheck_query(ctx, options):
    dqobj = DiarycheckDQ()
    return dqobj.process(**options)


@bind_context(uri_pre + '/get_message')
def get_message(ctx, level):
    message_data = []
    diary_message = DiaryMessage.objects.filter(level=level).filter(is_delete=False)
    for message in diary_message:
        data = {
            'id': message.id,
            'title': message.title,
            'description': message.description,
            'message': message.message,
        }
        message_data.append(data)

    return message_data


@transaction.atomic
@bind_context(uri_pre + '/aduit_diary')
def aduit_diary(ctx, diarycheck):
    user = ctx.session.user
    person = user.person
    if diarycheck:
        content_level = diarycheck['content_level']
        diary_check = DiaryCheck(
            diary_id=diarycheck['diary_id'],
            person_id=person.id.hex,
            check_time=datetime.now(),
            content_level=diarycheck['content_level'],
            check_content=diarycheck['check_content'],
            send_message=diarycheck['send_message'],
            title=diarycheck['title']
        )
        diary_check.save()
        diary = Diary.objects.get(id=diarycheck['diary_id'])
        pre_content_level = diary.content_level
        if content_level == DIARY_CONTENT_LEVEL.ILLEGAL:
            if diary:
                diary.is_online = False
                diary_update_doctor_messages_status(ids=[diary.id], data_type=INDEX_CARD_TYPE.DIARY)
        diary.audit_status = DIARY_AUDIT_STATUS.AUDITED
        diary.content_level = content_level
        diary.audit_time = datetime.now()
        diary.save()
        # push signal到mimas
        if (pre_content_level != diarycheck['content_level'] and
                diarycheck['content_level'] in [DIARY_CONTENT_LEVEL.FINE, DIARY_CONTENT_LEVEL.EXCELLENT]):
            if diary.is_operation:
                service_type = SERVICE_TYPE.OPERATION
            else:
                service_type = SERVICE_TYPE.NO_OPERATION

            EventDispatcher.sent_diary_content_level_change_signal(
                user_id=ctx.session.user.id,
                diary_id=diary.id,
                author_id=diary.user_id,
                service_type=service_type,
                pre_level=pre_content_level,
                now_level=diarycheck['content_level'],
            )
    return diary_check.id


@bind_context(uri_pre + '/get_aduit_one')
def get_aduit_one(ctx, diary_id):
    diary_check = DiaryCheck.objects.filter(diary_id=diary_id).order_by('-check_time')
    if diary_check:
        diary_check = diary_check[0]
        options = {
            'fields': None,
            'excludes': None,
            'expands': None,
        }
        user = UserService.get_user_by_person_id(diary_check.person_id.hex)
        person_name = user.nickname
        content = DIARY_CONTENT_LEVEL.getDesc(diary_check.content_level)
        diary_check = to_dict(diary_check, **options)
        diary_check['person'] = person_name
        diary_check['content_level'] = content
        diary_check['check_time'] = str(diary_check['check_time']).split('.')[0]
    else:
        diary_check = None
    return diary_check


@bind_context(uri_pre + '/get_cover')
def get_diary_cover(ctx, diary_id):
    try:
        diary = Diary.objects.get(id=diary_id)
    except:
        return
    diary_date = {
        'pre_image': '',
        'post_image': '',
        'id': diary.id
    }
    diary_cover = diary_num_and_cover_by_id(id=diary.id).get('cover')
    for image in diary_cover:
        if image['desc'] == 'Before':
            diary_date['pre_image'] = get_full_path(image['image'], ('-w', '-thumb'))
        else:
            diary_date['post_image'] = get_full_path(image['image'], ('-w', '-thumb'))
    return diary_date


@bind_context(uri_pre + '/rank/export_excel')
def rank_export_top(ctx):
    """
    导出首页日记本排序top1000条数据
    create by chenfeifei 2017-01-17
    :param ctx:
    :return:
    """
    user = ctx.session.user
    export_diary_rank_top1000.delay(user.email)


@bind_context(uri_pre + '/rank_list_update')
def rank_list_update(ctx, data):
    """
    首页日记本排序干预系统列表批量修改加权值
    create by chenfeifei 2017-01-17
    :param ctx:
    :param data: [{'key': diary_id, 'additional_score': int}]
    :return: diary_ids
    """
    result = []
    for obj in data:
        try:
            diary_rank, _ = DiaryRank.objects.get_or_create(diary_id=obj['key'])
            diary_rank.additional_score = obj['additional_score']
            diary_rank.save()
            result.append(diary_rank.diary_id)
        except:
            continue
    return result


@bind_context(uri_pre + '/import_excel')
def import_excel(ctx, data):
    """
    导入excel批量日记本关联美购
    create by zhouyang 2017-03-21
    :param ctx:
    :param data: [{'diary_id': diary_id, 'service_id': service_id}]
    """
    result = []
    error_result = []
    for index, obj in enumerate(data):
        try:
            if obj['diary_id'] and obj['service_id']:
                diary = Diary.objects.get(pk=obj['diary_id'])
                service = Service.objects.get(pk=obj['service_id'])

                diary.service_id = service.id
                diary.doctor_id = service.doctor_id
                diary.hospital_id = service.doctor.hospital_id
                diary.save(update_fields=['service_id', 'doctor_id', 'hospital_id'])
                result.append(diary.id)
            else:
                error_result.append(index)
        except Service.DoesNotExist:
            error_result.append(index)
            continue
        except Diary.DoesNotExist:
            error_result.append(index)
            continue

    return result, error_result


@bind_context(uri_pre + '/upload_excel')
def upload_excel(ctx, data):
    """
    获取excel中日记本已关联的美购
    create by zhouyang 2017-03-21
    :param ctx:
    :param data: [[diary_id, meigou_id]]
    """
    resp_data = list()
    for item in data:
        if not any(item):
            continue
        diary_id, service_id = item
        try:
            diary = Diary.objects.get(pk=diary_id)
            item.append(diary.service_id or '-')
            item.append(diary.raw_hospital or '-')
            diary_service = Service.objects.filter(id=diary.service_id).first()
            if diary_service:
                item.append(diary_service.doctor.hospital.name)
            else:
                item.append('-')
        except Diary.DoesNotExist:
            item += ['-', '-', '-']

        try:
            service = Service.objects.get(pk=service_id)
            item.append(service.doctor.hospital.name or '-')
        except Service.DoesNotExist:
            item.append('-')
        resp_data.append(item)
    return resp_data


@bind_context(uri_pre + '/new_upload_excel')
def new_upload_excel(ctx, data):
    resp_data = list()
    for item in data:
        if not any(item):
            continue
        service_id = item[0]
        doctor_id = item[3]
        try:
            service = Service.objects.get(pk=service_id, doctor_id=doctor_id)
            doctor_name = service.doctor.name
            hospital_id = service.doctor.hospital_id if service.doctor.hospital_id else ''
            hospital_name = service.doctor.hospital.name if service.doctor.hospital else ''
            start_time = service.start_time.strftime("%Y-%m-%d %H:%S:%M") if service.start_time else ''
            item.extend([hospital_id, doctor_name, hospital_name, start_time])
        except Service.DoesNotExist:
            item.extend(["", "", "", ""])
        resp_data.append(item)
    return resp_data


@bind_context(uri_pre + '/new_import_excel')
def new_import_excel(ctx, data):
    rpc_mimas = get_rpc_remote_invoker()
    service_ids, result, error_result_v1, send_data, success_list = [], [], [], [], []
    username_fw = AntiSpamService.get_filtered_words(filter_type=FILTER_WORD_TYPE.USER_NAME)
    content_fw = AntiSpamService.get_filtered_words(filter_type=FILTER_WORD_TYPE.TOPIC_CONTENT)
    for index, obj in enumerate(data):
        last_name = obj.pop('last_name', '')
        if filterword_function(fw=username_fw, content=last_name) or \
                filterword_function(fw=content_fw,content=obj['content']):
            error_result_v1.append(index)
        elif (obj['service_id'] and obj['hospital_id'] and last_name):
            user_id = user_create.func(ctx, last_name=last_name, is_puppet=True).get('user_id')

            # 马甲用户创建以后，需要往ClassifyUser添加一条记录
            ClassifyUser.objects.get_or_create(user_id=user_id, classify=USER_CLASSIFY.MODEL)

            obj.update({'user_id': user_id})
            service_ids.append(obj['service_id'])
            send_data.append(obj)
            success_list.append(obj['service_id'])
        else:
            error_result_v1.append(index)
    try:
        services_tags = get_services_tag_name_by_service_ids.func(service_ids=service_ids)
        rpc_mimas['diary/batch_create_inner'](data=send_data, services_tags=services_tags).unwrap()
    except Exception as e:
        raise e

    return success_list, error_result_v1