#!/usr/bin/env python
# coding=utf-8

import datetime

from django.db.models import Q, Max, Count
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 DIARY_CONTENT_LEVEL, INDEX_CARD_TYPE

from talos.models.diary import Diary, DiaryTag
from talos.models.topic import Problem, TopicReply
from talos.models.doctor import DoctorMessageList
from utils.rpc import gen, rpc_client, logging_exception
from talos.libs.datetime_utils import get_timestamp_or_none
from talos.services.user import UserService


@bind('diary/tags/filter_by_doctor_org')
def get_tags_for_doctor_organization(doctor_id=None, organization_id=None):
    '''
    get tag filter for Doc or Org
    :param doctor_id:
    :param organization_id:
    :return:
    '''
    if not doctor_id and not organization_id:
        return gen(CODES.PARAMS_INCOMPLETE)
    elif doctor_id and organization_id:
        # doctor_id and organization_id must be exclusive
        return gen(CODES.PARAMS_INVALID)
    else:
        re_data = {'tag_ids': []}
        q_diary = Q(is_online=True)
        if doctor_id:
            q_diary &= Q(doctor_id=doctor_id)
        else:
            q_diary &= Q(hospital_id=organization_id)

        rough_diary_set = Diary.objects.filter(q_diary)

        if rough_diary_set:
            diary_id_set_with_normal_topic = Problem.objects.filter(
                is_online=True,
                flag__exact='n',
                diary__in=rough_diary_set
            ).values_list('diary_id', flat=True)
            if diary_id_set_with_normal_topic:
                tag_ids = DiaryTag.objects.filter(
                    diary_id__in=list(diary_id_set_with_normal_topic)
                ).values_list('tag_id', flat=True)
                re_data['tag_ids'] = list(tag_ids)

        return re_data


@bind('diary/list_by_doctor_ids')
def diary_list_by_doctor_ids(doctor_ids):
    if len(doctor_ids) > 100:
        return gen(CODES.OPERATION_NOT_SUPPORTED)

    diary_queryset = Diary.objects.filter(
        doctor_id__in=doctor_ids,
        is_online=True,
        topics__isnull=False,
        topics__flag='n',
        topics__is_online=True,
    ).distinct()

    result = {'diarys': []}

    for diary in diary_queryset:
        if diary.content_level in (DIARY_CONTENT_LEVEL.EXCELLENT, DIARY_CONTENT_LEVEL.FINE, DIARY_CONTENT_LEVEL.BETTER):
            result['diarys'].append({'id': diary.id, 'title': diary.title})

    return result


@bind("diary/count_by_doctor_ids")
def get_diary_count_by_doctor_ids(doctor_ids, start_time, end_time):
    """
    通过 doctor_ids 获取 起始时间到截止时间内的日记本数
    :param doctor_ids: 医生id 列表 []
    :param start_time: 起始时间 str
    :param end_time: 截止时间 str
    :return: dict {}
    """
    result = {
        "total": 0,  # 总数
        "four_stars_num": 0,  # 4星总数
        "five_stars_num": 0,  # 5星总数
    }

    if not (doctor_ids and start_time and end_time):
        return result
    start_time = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
    end_time = datetime.datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")

    query = Q(is_online=True, doctor_id__in=doctor_ids, created_time__range=[start_time, end_time])
    diaries = Diary.objects.filter(query)
    result["total"] = diaries.count()
    result["four_stars_num"] = diaries.filter(content_level=DIARY_CONTENT_LEVEL.FINE).count()
    result["five_stars_num"] = diaries.filter(content_level=DIARY_CONTENT_LEVEL.EXCELLENT).count()

    return result


@bind("topic/list_messages_by_doctor_id")
def get_doctor_push_diary_by_doctor_id(doctor_id, sort_type=None, offset=0, count=10):

    if sort_type == "invite_time":
        sort = '-created_time'
    else:
        sort = '-created_time'

    query = Q(is_online=True, diary_id__isnull=False, topic_id__isnull=False, doctor_id=doctor_id)

    messages_qs = DoctorMessageList.objects.filter(query).order_by(sort)

    cnt = messages_qs.count()
    if not cnt:
        return {"total": cnt, "topics": []}

    messages = messages_qs[offset: offset + count].select_related("diary", "topic")
    users = UserService.get_users_by_user_ids([item.user_id for item in messages])

    cities_ids = [user.current_city_id for user in users.values() if user.current_city_id]
    cities = {}
    if cities_ids:
        try:
            cities = rpc_client['api/city/city_by_ids'](city_ids=cities_ids).unwrap()
        except:
            logging_exception()

    # 获取问题最后回答时间
    replies = TopicReply.objects.filter(is_online=True, problem_id__in=[ms.topic_id for ms in messages]) \
        .values_list("problem_id").annotate(reply_time=Max('reply_date'))
    reply_time_info = {topic_id: reply_time for topic_id, reply_time in replies}

    # 获取一级评论数
    replies = TopicReply.objects.filter(problem_id__in=[ms.topic_id for ms in messages], is_online=True,
                                        problem__isnull=False, commented_reply__isnull=True) \
        .values_list("problem_id").annotate(cnt=Count('*'))
    reply_cnt_info = {topic_id: cnt for topic_id, cnt in replies}

    res = {"total": cnt, "topics": []}
    for item in messages:
        user = users.get(item.user_id)
        info = {
            "id": item.topic.id,
            "title": item.topic.answer and escape(item.topic.answer) or '',
            "diary_title": item.diary.title,
            "diary_id": item.diary_id,
            "created_time": get_timestamp_or_none(item.topic.created_time),
            "update_time": get_timestamp_or_none(reply_time_info.get(item.topic.id)),
            "reply_num": reply_cnt_info.get(item.topic.id, 0),
            "status": item.process_status,
            "author": {
                "id": user.id,
                "nickname": user.nickname,
                'current_city_id': user.current_city_id,
                'current_city_name': cities.get(user.current_city_id, {}).get("name"),
                'city_id': user.city_id,
                'city_name': user.city_name,
            }
        }
        res["topics"].append(info)

    return res


@bind("diary/doctor_diary_question/status")
def update_doctor_diary_question_status(data_ids=None, data_type=INDEX_CARD_TYPE.QUESTION, status=False):

    if not data_ids:
        gen(CODES.PARAMS_INCOMPLETE)

    query = Q()
    if data_type == INDEX_CARD_TYPE.QUESTION:
        query &= Q(question_id__in=data_ids)
    elif data_type == INDEX_CARD_TYPE.DIARY_TOPIC:
        query &= Q(topic_id__in=data_ids)
    elif data_type == INDEX_CARD_TYPE.DIARY:
        query &= Q(diary_id__in=data_ids)
    else:
        gen(CODES.PARAMS_INVALID)

    DoctorMessageList.objects.filter(query).update(is_online=status)

    return True


@bind("diary/merchant_id/get_by_diary_id")
def get_merchant_by_diary_id(diary_id):
    """CPC获取商户内容专属"""
    if not diary_id:
        return

    diary = Diary.objects.filter(id=diary_id).first()
    if not diary:
        return

    doctor_id, hospital_id = diary.doctor_id, diary.hospital_id
    from utils.rpc import get_rpc_invoker
    rpc = get_rpc_invoker()

    doctor_info = rpc['doctor/get_info/by_id'](doctor_id=doctor_id).unwrap() or {}

    return doctor_info.get("merchant_id", "")


@bind('mimas/tractate/community_promote_account_by_ids')
def get_cpc_community_promote_account(related_ids):
    """
    根据日记本id,过滤出其中在线的id
    :param related_ids:
    :return:
    """
    effective_related_ids = Diary.objects.filter(id__in=related_ids).filter(is_online=True).values('id')
    res = [id['id'] for id in effective_related_ids]
    return res