# -*- coding: utf-8 -*-
import json
import logging
import time
from datetime import datetime, timedelta

from django.conf import settings
from gm_types.doctor import DOCTOR_TITLE_TYPE

from api.tool.log_tool import logging_exception
from gm_protocol import GmProtocol, GmdoctorProtocol
from gm_types.consultation import CONSULTATION_EVENT_TYPE
from gm_types.error import ERROR
from gm_types.gaia import PLATFORM_CHOICES, TAG_V3_TYPE
from gm_types.msg import MESSAGE_TYPE, CONVERSATION_TYPE
from gm_types.push import PUSH_INFO_TYPE, J_TYPE, AUTOMATED_PUSH, PUSH_URGENCY
from helios import RPCSystemException, RPCFaultException

from api.models import User
from agile.models import TagV3
from api.models import MessageBlackUser, Message, Doctor, City, ServiceTag, Doctor, TagRelation
from api.tool.datetime_tool import get_datetime
from api.tool.image_utils import get_full_path
from api.tool.user_tool import get_user_from_context
from api.bridge import internal_message_send
from rpc.context import get_rpc_remote_invoker
from rpc.decorators import bind_context
from rpc.exceptions import GaiaRPCFaultException
from api.tool.image_utils import get_full_path
from api.tool.user_tool import filter_user_nick_name
from rpc.tool.error_code import gen, CODES
from social import SocialInfo


DOCTOR_DEFAULT_PORTRAIT_URL = 'http://hera.s.igengmei.com/2015/12/24/a9fcb0f072'


def build_consultation_counsel_push_event_alert(noti_type):
    if noti_type == CONSULTATION_EVENT_TYPE.INVETED_JOIN:
        alert = '你收到一个视频面诊邀请'
    elif noti_type == CONSULTATION_EVENT_TYPE.REJECT_INVITE:
        alert = '你的视频面诊邀请被拒绝'
    elif noti_type == CONSULTATION_EVENT_TYPE.RECOMMENDED_BAG_UPDATE:
        alert = '你的视频面诊美购有更新'
    elif noti_type == CONSULTATION_EVENT_TYPE.USER_DISPATCH:
        alert = '你有新的面诊派单，点击抢单'
    elif noti_type == CONSULTATION_EVENT_TYPE.USER_INVENTED_JOIN:
        alert = '你收到一个视频面诊邀请'
    else:
        alert = '你的视频面诊美购有更新'
    return alert


def build_consultation_counsel_push_event_extra(consultation_record_id, noti_type):
    base = {
        'type': PUSH_INFO_TYPE.CONSULTATION,
        'noti_type': noti_type,
        'consultation_record_id': consultation_record_id,
        'android_sound_file_name': 'videoTelephone.aiff',
    }

    if noti_type == CONSULTATION_EVENT_TYPE.USER_DISPATCH:
        gm_protocol = GmProtocol()
        # base.update(pushUrl=gm_protocol.diagnosis_workbench_dispatch())
        base.update(pushUrl='gengmei://diagnosis_workbench_dispatch')
    return base


@bind_context('api/consultation_counsel/push_noti_call_out')
def push_noti_call_out(ctx, target_user_id, consultation_record_id, noti_type):
    alert = build_consultation_counsel_push_event_alert(noti_type)
    extra = build_consultation_counsel_push_event_extra(consultation_record_id, noti_type)
    platform = [PLATFORM_CHOICES.ANDROID, PLATFORM_CHOICES.IPHONE]

    rpc_invoker = get_rpc_remote_invoker()
    res = rpc_invoker['push2/push/user/notification/uids'](
        user_ids=[target_user_id],
        platform=platform,
        alert=alert,
        extra=extra,
        push_time=int(time.time()),
    ).unwrap()
    logging.info("push_noti_call_out: {}, {}, {}".format(
        target_user_id,
        res.get('task_id', '') if res else '',
        json.dumps(extra)))
    return dict(
        code=0 if res and res.get('task_id') else 1,
        data=res
    )


@bind_context('api/consultation_counsel/push_event')
def consultation_counsel_push_event(ctx, target_user_id, consultation_record_id, noti_type,
                                    time_to_live=None, ios_sound_file_name=None):
    '''
    通知 + 自定义消息， 通过一条推送发送
    :param: target_user_id: 接收方用户id
    :param: consultation_record_id: 面诊记录id
    :param: noti_type: 事件类型,参考 http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=33601111#id-%E6%A8%A1%E5%9D%972%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89-7.%E8%A7%86%E9%A2%91%E9%80%9A%E8%AF%9D%E6%B5%81%E7%A8%8B%E4%BA%8B%E4%BB%B6%E4%B8%8A%E6%8A%A5%E6%8E%A5%E5%8F%A3%EF%BC%9A
    :param: time_to_live: 超时时间，单位秒，如果不传，push服务会设置为默认3天
    '''
    check_params_message = ''
    if not target_user_id:
        check_params_message = 'target_user_id不能为空'
    if not noti_type:
        check_params_message = 'noti_type不能为空'
    if noti_type != CONSULTATION_EVENT_TYPE.USER_DISPATCH and not consultation_record_id:
        check_params_message = 'consultation_record_id不能为空'

    if check_params_message:
        raise GaiaRPCFaultException(ERROR.INVALID_PARAMS,
                                    check_params_message,
                                    None)

    alert = build_consultation_counsel_push_event_alert(noti_type)
    extra = build_consultation_counsel_push_event_extra(consultation_record_id,
                                                        noti_type)
    platform = [PLATFORM_CHOICES.ANDROID, PLATFORM_CHOICES.IPHONE]

    log = {
        "event_type": noti_type,
        "target_uid": target_user_id,
        "consult_id": consultation_record_id,
        "call_timestamp": int(time.time() * 1000),
        "msg_id": ""
    }

    j_type = J_TYPE.MESSAGE
    if noti_type in [CONSULTATION_EVENT_TYPE.INVETED_JOIN,
                     CONSULTATION_EVENT_TYPE.USER_INVENTED_JOIN]:
        j_type = J_TYPE.NOTIFICATION_AND_MESSAGE
    elif noti_type == CONSULTATION_EVENT_TYPE.USER_DISPATCH:
        j_type = J_TYPE.NOTIFICATION

    others = {}
    if time_to_live is not None:
        others = dict(time_to_live=time_to_live)
    if ios_sound_file_name:
        others.update(ios_sound_file_name=ios_sound_file_name)

    api_endpoint = 'push2/push/user/automated_push/uids'
    rpc_invoker = get_rpc_remote_invoker()
    if not isinstance(target_user_id, list):
        target_user_id = [target_user_id]
    try:
        res = rpc_invoker[api_endpoint](
            user_ids=target_user_id,
            push_type=AUTOMATED_PUSH.CONSULTATION,
            platform=platform,
            alert=alert,
            extra=extra,
            push_time=int(time.time()),
            silent=False,
            urgency=PUSH_URGENCY.URGENT,
            j_type=j_type,
            others=others
        ).unwrap() or {}

        logging.info("consultation_counsel_push_event, target_user_id: {}, res: {}, extra:{}".format(
            target_user_id,
            json.dumps(res) if res else '',
            json.dumps(extra)))
    except (RPCFaultException, RPCSystemException) as e:
        log['success'] = False
        logging_exception()
        res = {}
    else:
        log['success'] = True
        log['msg_id'] = res.get('msg_id', '')

    ctx.logger.app(**log)
    return dict(
        code=0 if res else 1,
        data=res
    )


def send_private_message(ctx, sender_user_id, target_user_id, msg_type, content, is_system=1):
    if not sender_user_id:
        gen(ERROR.MESSAGE_UNKNOWN_USER)

    before24hour = datetime.now() - timedelta(days=1)
    if MessageBlackUser.objects.filter(user_id=sender_user_id,
                                       created_time__gte=before24hour):
        gen(ERROR.MESSAGE_DOUBTED_CONVERSATION)

    res = internal_message_send(
        sender_user_id=sender_user_id,
        target_user_id=target_user_id,
        conversation_type=CONVERSATION_TYPE.MESSAGE,
        msg_type=msg_type,
        content=content,
        push_stat_labels={'event_type': 'push', 'event': 'received_private_msg'},
        is_system=is_system,
    )

    if res['error'] == ERROR.MESSAGE_INVALID_USER:
        ctx.session.do_logout()

    if res['error'] != ERROR.SUCCESS:
        gen(res['error'])

    return {
        'error':0,
        'message':'ok',
        'data':{
            'msg': res['msg'],
        }
    }


@bind_context('api/consultation_counsel/send_replay_message')
def send_replay_message(ctx, sender_user_id, target_user_id, consultation_record_id, video_preview_url,
                        msg_type=MESSAGE_TYPE.CONSULTATION_COUNSEL_REPLAY, is_system=1):

    if not video_preview_url.startswith('http://') and not video_preview_url.startswith('https://'):
        domain = settings.QINIU_LIVE_DIANBO_DOMAIN
        if not domain.endswith('/'):
            domain += '/'
        video_preview_url = '{}{}'.format(domain, video_preview_url)

    content = dict(
        consultation_record_id=consultation_record_id,
        video_preview_url=video_preview_url
    )
    return send_private_message(ctx,
                                sender_user_id=sender_user_id,
                                target_user_id=target_user_id,
                                msg_type=msg_type,
                                content=content,
                                is_system=is_system)


@bind_context('api/consultation_counsel/send_call_cancel_message')
def send_replay_message(ctx, sender_user_id, target_user_id, msg_type=MESSAGE_TYPE.TEXT, is_system=1):
    content = {'text': u'视频面诊已取消'}
    return send_private_message(ctx,
                                sender_user_id=sender_user_id,
                                target_user_id=target_user_id,
                                msg_type=msg_type,
                                content=content,
                                is_system=is_system)


@bind_context('api/consultation_counsel/send_text_message')
def send_text_message(ctx, sender_user_id, target_user_id, text, msg_type=MESSAGE_TYPE.TEXT, is_system=1):
    content = {'text': text}
    return send_private_message(ctx,
                                sender_user_id=sender_user_id,
                                target_user_id=target_user_id,
                                msg_type=msg_type,
                                content=content,
                                is_system=is_system)


@bind_context('api/consultation_counsel/section_tags')
def section_tags(ctx):
    # 一级部位标签, 不是咨询项目
    qs = TagV3.objects.filter(aggregate_type=TAG_V3_TYPE.FIRST_POSITION).all()
    return [dict(
        id=tag.id,
        name=tag.name,
        homoionym=tag.homoionym,
    ) for tag in qs]


def is_fans_of_doctor(normal_user_id, doctor_user_id):
    social_info = SocialInfo(uid=normal_user_id)
    return social_info.is_following_user(uid=doctor_user_id)


@bind_context('api/consultation_counsel/is_fans_of_user')
def is_fans_of_user(ctx, user_id):
    is_follow = False
    if ctx.session.user.id:
        is_follow = is_fans_of_doctor(ctx.session.user.id, user_id)
    return is_follow


@bind_context('api/consultation_counsel/get_doctor_info_by_user_id')
def get_doctor_info_by_user_id(ctx, user_id):
    doctor = Doctor.objects.filter(user_id=user_id).first()
    if not doctor:
        return None

    info = doctor.doctor_detail_v2(need_intro=True)

    city_id = doctor.hospital.city.id if doctor.hospital else None
    if not city_id:
        city_name = ''
    else:
        qs = City.objects.filter(id=city_id).values("id", "name")
        city_name = qs[0]['name'] if qs else ''

    hospital_name = doctor.hospital.name if doctor.hospital else ''

    is_follow = False
    if ctx.session.user.id:
        is_follow = is_fans_of_doctor(ctx.session.user.id, user_id)
    # doctor_user = doctor.user
    # is_follow = doctor_user.fans.filter(follow=ctx.session.user, bond=True).exists()

    doctor_extra = doctor.extra()
    employment_time = doctor_extra.working_year if doctor_extra else 0

    title = DOCTOR_TITLE_TYPE.getDesc(doctor.title) if doctor.title and doctor.title != '0' else ''
    data = dict(
        name=info["name"],
        gender=0,
        title=title,
        portrait=get_full_path(info["portrait"]) or DOCTOR_DEFAULT_PORTRAIT_URL,
        city_name=city_name,
        hospital_id=doctor.hospital_id,
        hospital_name=info["hospital_name"],
        is_follow=is_follow,
        employment_time=employment_time,
    )
    return data


@bind_context('api/consultation_counsel/doctor_info_by_user_id')
def doctor_info_by_user_id(ctx, user_id):
    doctor = Doctor.objects.filter(user_id=user_id).first()
    if not doctor:
        return None

    is_follow = False
    if ctx.session.user.is_authenticated():
        is_follow = is_fans_of_doctor(ctx.session.user.id, user_id)

    data = dict(
        user_id=doctor.user_id,
        name=doctor.name,
        is_follow=is_follow,
        portrait=get_full_path(doctor.portrait) or DOCTOR_DEFAULT_PORTRAIT_URL,
    )
    return data


@bind_context('api/consultation_counsel/user_info_by_user_id')
def user_info_by_user_id(ctx, user_id):

    try:
        user = User.objects.get(pk=user_id, is_active=True)
    except (User.DoesNotExist, ValueError):
        return gen(CODES.USER_NOT_FOUND)

    return {
        "user_id": user.id,
        "nick_name": filter_user_nick_name(user) or u'',
        "portrait": user.userextra.get_portrait() if user.userextra else '',
        "phone": user.userextra.phone if user.userextra else "",
    }


@bind_context('api/consultation/batch_create_counsellor')
def consellor_create(ctx, doctor_ids):
    tags = settings.FACE_CONSULT_TAGS
    tag_relas = TagRelation.objects.filter(
        parent_id__in=tags
    ).values("parent_id", "child_id")

    relations = {tag_id: [tag_id] for tag_id in tags}
    for tag_rela in tag_relas:
        relations[tag_rela["parent_id"]].append(tag_rela["child_id"])

    counsellors = []
    doctor_ids = doctor_ids.split(',')
    query = Doctor.objects.filter(id__in=doctor_ids)
    for doctor in query:
        # 获取标签数量，并且排序获取前三
        doctor_tags_service_cnt = {}
        for tag_id, relation_ids in relations.items():
            service_cnt = ServiceTag.objects.filter(
                service__doctor_id=doctor.id, tag_id__in=relation_ids, service__is_online=True
            ).count()
            if not service_cnt:
                continue
            doctor_tags_service_cnt[tag_id] = service_cnt
        good_ats = sorted(doctor_tags_service_cnt.items(), key=lambda d: - d[1])

        good_at = json.dumps([i for i, _ in good_ats[:3]])

        counsellor = {
            "doctor_id": doctor.id,
            "user_id": doctor.user_id,
            "merchant": doctor.merchant and doctor.merchant.id or None,
            "good_at": good_at,
        }
        counsellors.append(counsellor)

    try:
        rpc_invoker = get_rpc_remote_invoker()
        rpc_invoker["diagnosis/batch_create_counsellor"](counsellors_info=counsellors).unwrap()
    except:
        return gen(ERROR.UPDATE_FAIL)


@bind_context('api/consultation_counsel/user_follow_info')
def user_follow_info(ctx, user_ids):
    """
    获取用户关注关系
    :param user_ids: 用户ID列表
    :return:
    """
    user = get_user_from_context(ctx)
    if not user:
        return {}

    social_info = SocialInfo(uid=user.id)
    follow_info = social_info.is_following_users(uids=user_ids)

    return follow_info


@bind_context('api/consultation_counsel/user_fans_count')
def user_fans_count(ctx, user_id):
    """ 获取面诊师对应用户的粉丝数 """
    num = 0
    try:
        social_info = SocialInfo(uid=user_id)
        num = social_info.get_new_follow_count()
    except Exception:
        logging_exception()
    return num


@bind_context("api/consultation_counsel/doctor_ids_by_bd")
def get_doctor_ids_by_bd(ctx, business_partener_id):
    """ 根据商务ID 获取对应负责的医生ID """

    doctor_ids = Doctor.objects.filter(
        business_partener_id=business_partener_id
    ).values_list("id", flat=True)

    return list(doctor_ids)
