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

from __future__ import unicode_literals, absolute_import
from datetime import date, timedelta

from gm_types.doctor import DOCTOR_MESSAGE_TYPE, DOCTOR_ORDER_MESSAGE_TYPE
from gm_types.error import ERROR
from gm_types.trade import STATEMENT_OPERATION_TYPE

from api.models import ServiceRegister, model_to_dict
from hippo.models import Doctor, MESSAGE_TYPE_CONTENT
from pay.models import StatementAll, ServiceSnapshot
from pay.models import StatementAllOperation
from rpc.decorators import bind_context, bind
from rpc.exceptions import GaiaRPCFaultException
from ..models.doctormessage import DoctorMessage, OrderMessage
from api.models.order import Order, RefundOrder
from ..utils import get_merchant


def add_order_message(type, info_ids):
    """
    :param type: 取自gm_types.doctor DOCTOR_ORDER_MESSAGE_TYPE，0为订单、1为退款单
    :param info_id: 订单 or 退款单的ID
    :return:
    """

    if type == DOCTOR_ORDER_MESSAGE_TYPE.ORDER:
        iid2did = {o[0]: o[1] for o in Order.objects.filter(
            id__in=info_ids).values_list('id', 'service__doctor_id')}
    else:
        iid2did = {o[0]: o[1] for o in RefundOrder.objects.filter(
            id__in=info_ids).values_list('id', 'order__service__doctor_id')}

    dids = set(iid2did.values())

    did2mid = {}
    for did in dids:
        merchant = get_merchant(did)
        if merchant:
            did2mid[did] = merchant.id

    to_insert_message = []

    for iid in info_ids:
        if iid in iid2did:
            did = iid2did[iid]
            m = OrderMessage(type=type, info_id=iid, doctor_id=did)
            if did and did in did2mid:
                m.merchant_id = did2mid[did]
            to_insert_message.append(m)

    OrderMessage.objects.bulk_create(to_insert_message)
    for item in to_insert_message:
        try:
            from services.notify import notify
            notify('deal/add', doctor_id=item.doctor.id, data={})
        except:
            continue


@bind_context('doctor/message/system', login_required=True)
def get_message_system(ctx, doctor_id, start_num=0, count=10):
    """
    系统消息列表（除公告和协议）
    :param ctx:
    :param doctor_id:
    :param start_num:
    :param count:
    :return:
    """
    messages = DoctorMessage.objects.filter(doctor_id=doctor_id).order_by('-created_time')
    message_list = list()
    for message in messages[start_num: start_num + count]:
        message_data = {
            'id': message.id,
            'content': message.content,
            'type': message.type,
            'time': message.created_time.strftime('%Y-%m-%d %H:%M:%S'),
            'info_id': message.info_id,
            'is_read': message.is_read,
            'can_view': True
        }
        message_list.append(message_data)

    data = {
        'total': messages.count(),
        'message_list': message_list
    }
    return data


@bind_context('doctor/message/not_read', login_required=True)
def get_message_no_read(ctx, doctor_id, start_num=0, count=10):
    """
    未读消息列表（除协议）
    :param ctx:
    :param doctor_id:
    :param start_num:
    :param count:
    :return:
    """

    messages = DoctorMessage.objects.filter(doctor_id=doctor_id, is_read=False) \
        .order_by('-created_time')
    message_list = list()
    for message in messages[start_num: start_num + count]:
        message_data = {
            'id': message.id,
            'content': message.content,
            'type': message.type,
            'time': message.created_time.strftime('%Y-%m-%d %H:%M:%S'),
            'info_id': message.info_id,
            'can_view': True
        }
        message_list.append(message_data)

    data = {
        'total': messages.count(),
        'message_list': message_list
    }
    return data


@bind_context('doctor/message/index', login_required=True)
def get_message_index(ctx, doctor_id):
    """
    首页未读消息列表（除公告和协议）
    :param ctx:
    :param doctor_id:
    :return:
    """
    messages = DoctorMessage.objects.filter(doctor_id=doctor_id, is_read=False) \
        .exclude(type__in=[DOCTOR_MESSAGE_TYPE.CPT_THREE_DAY_REMIND, DOCTOR_MESSAGE_TYPE.CPT_THREE_DAY_REMIND_POP_UPS]) \
        .order_by('-created_time')
    message_list = list()
    for message in messages[0: 3]:
        message_data = {
            'id': message.id,
            'content': message.content,
            'type': message.type,
            'time': message.created_time.strftime('%Y-%m-%d %H:%M:%S'),
            'info_id': message.info_id,
            'can_view': True
        }
        message_list.append(message_data)
    # 获取弹窗消息
    start_date = date.today()
    end_date = start_date + timedelta(days=1)
    pop_ups_messages = DoctorMessage.objects.filter(doctor_id=doctor_id,
                                                    type__in=[DOCTOR_MESSAGE_TYPE.CPT_ONLINE_REMIND,
                                                              DOCTOR_MESSAGE_TYPE.CPT_THREE_DAY_REMIND],
                                                    created_time__range=(start_date, end_date)).order_by('created_time')
    for message in pop_ups_messages:
        message_data = {
            'id': message.id,
            'content': message.content,
            'type': message.type,
            'time': message.created_time.strftime('%Y-%m-%d %H:%M:%S'),
            'info_id': message.info_id,
            'can_view': False
        }
        message_list.append(message_data)
    data = {
        'total': messages.count(),
        'message_list': message_list
    }
    return data


@bind_context('doctor/message/read', login_required=True)
def record_message_is_read(ctx, message_id):
    """
    消息已读调用
    :param ctx:
    :param message_id:
    :return:
    """
    try:
        message = DoctorMessage.objects.get(id=message_id)
        message.is_read = True
        message.save(update_fields=['is_read'])
        return message.id
    except DoctorMessage.DoesNotExist:
        return 0


@bind_context('doctor/cpt_message/pop_ups', login_required=True)
def record_message_is_read(ctx, message_id):
    """
    cpt上线提醒弹窗调用，表示已经弹窗了
    :param ctx:
    :param message_id:
    :return:
    """
    try:
        message = DoctorMessage.objects.get(id=message_id)
        if message.type == DOCTOR_MESSAGE_TYPE.CPT_THREE_DAY_REMIND:
            message.type = DOCTOR_MESSAGE_TYPE.CPT_THREE_DAY_REMIND_POP_UPS
        if message.type == DOCTOR_MESSAGE_TYPE.CPT_ONLINE_REMIND:
            message.type = DOCTOR_MESSAGE_TYPE.CPT_ONLINE_REMIND_POP_UPS
        message.save(update_fields=['type'])
        return message.id
    except DoctorMessage.DoesNotExist:
        return 0


@bind_context('doctor/message/order_refund', login_required=True)
def get_order_refund_message(ctx, doctor_id):
    order_messages = OrderMessage.objects.filter(
        doctor_id=doctor_id, is_push=False
    ).order_by('-created_time')
    message_list = list()

    order_messages_count = 0
    order_message_ids = []
    for order_message in order_messages:
        if order_message.type == DOCTOR_ORDER_MESSAGE_TYPE.ORDER:
            order_id = order_message.info_id
        else:
            order_id = RefundOrder.objects.get(id=order_message.info_id).order_id

        title = ServiceSnapshot.objects.filter(order_id=order_id).values_list('name', flat=True)[0]

        data = {
            'info_id': order_message.info_id,
            'title': title,
            'type': order_message.type
        }
        message_list.append(data)

    for message in order_messages:
        message.is_push = True
        message.save()
    result = {
        'total': order_messages_count,
        'info_list': message_list,
    }

    return result


@bind_context('doctor/message/cashback_expire')
def send_cashback_expire_noti(ctx, batch_user_data):
    message_type = DOCTOR_MESSAGE_TYPE.DOCTOR_CASHBACK_EXPIRE
    for doctor_data in batch_user_data:
        doctor_id = doctor_data.get('doctor_id')
        if not doctor_id:
            continue
        format_args = []
        invalidate_in_7_days = doctor_data.get('invalidate_in_7_days')
        if invalidate_in_7_days:
            format_args.append('有{}笔，共计{}元的返点即将在7日内到期清零，'.format(
                invalidate_in_7_days.get('records_count'),
                invalidate_in_7_days.get('total_cashback_surplus')
            ))
        else:
            format_args.append('')
        invalidate_in_3_days = doctor_data.get('invalidate_in_3_days')
        if invalidate_in_3_days:
            format_args.append('有{}笔，共计{}元的返点即将在3日内到期清零，'.format(
                invalidate_in_3_days.get('records_count'),
                invalidate_in_3_days.get('total_cashback_surplus')
            ))
        else:
            format_args.append('')
        content = MESSAGE_TYPE_CONTENT[message_type].format(*format_args)
        info = dict(
            type=message_type,
            content=content,
            doctor_id=doctor_id,
            merchant=get_merchant(doctor_id)
        )
        message = DoctorMessage.objects.create(**info)
        try:
            from services.notify import notify
            notify('system/add', doctor_id=doctor_id, data={})
        except Exception as e:
            pass


@bind_context('doctor/message/send_counsellor_audit_result_noti')
def send_counsellor_audit_result_noti(ctx, doctor_id, counllor_name, message_type):
    """
    @param ctx:
    @param doctor_id:  机构管理者的doctor_id
    @param counllor_name: 面诊师名字
    @param message_type: 通知类型
        COUNLLOR_INFO_AUDIT_PASS = (23, u'面诊师资料审核通过提醒')
        COUNLLOR_INFO_AUDIT_REJECT = (24, u'面诊师资料审核驳回提醒')
    """
    if not message_type or not message_type in [DOCTOR_MESSAGE_TYPE.COUNSELLOR_INFO_AUDIT_PASS,
                                          DOCTOR_MESSAGE_TYPE.COUNSELLOR_INFO_AUDIT_REJECT]:
        raise GaiaRPCFaultException(error=ERROR.INVALID_PARAMS, message='noti_type错误', data=None)
    
    if not counllor_name or not doctor_id:
        raise GaiaRPCFaultException(error=ERROR.INVALID_PARAMS, message='counllor_name,doctor_id不能为空', data=None)

    content = MESSAGE_TYPE_CONTENT[message_type].format(counllor_name)
    info = dict(
        type=message_type,
        content=content,
        doctor_id=doctor_id,
        merchant=get_merchant(doctor_id)
    )
    message = DoctorMessage.objects.create(**info)
    try:
        from services.notify import notify
        notify('system/add', doctor_id=doctor_id, data={})
    except Exception as e:
        pass


@bind_context('doctor/message/cashback_expire_prompt')
def cashback_expire_prompt(ctx, doctor_id):
    today_midnight = date.today()
    message = DoctorMessage.objects.filter(doctor_id=doctor_id,
                                 created_time__gt=today_midnight,
                                 created_time__lt=today_midnight+timedelta(1),
                                 type=DOCTOR_MESSAGE_TYPE.DOCTOR_CASHBACK_EXPIRE).last()
    if message:
        response_dict = model_to_dict(message)
        if 'content' in response_dict:
            response_dict['content'] = response_dict['content'].replace('【商桥消息】', '')
        message.is_read = True
        message.save()
        return response_dict
    return {}


@bind_context('doctor/message/add_message')
def add_message(ctx, info, message_info):
    merchant = get_merchant(info['doctor_id'])
    if merchant:
        info['merchant_id'] = merchant.id
    DoctorMessage.add_message(info, *message_info)


@bind_context('doctor/message/audit_statement')
def audit_statement_message(ctx, statement_ids):
    """
    对账单通过发消息
    :param ctx:
    :param statement_ids:
    :return:
    """
    statements = StatementAll.objects.filter(id__in=statement_ids)
    for statement in statements:
        merchant = get_merchant(statement.doctor.id)
        info = {
            'type': DOCTOR_MESSAGE_TYPE.STATEMENT_CONFIRM,
            'info_id': statement.id,
            'doctor_id': statement.doctor.id,
        }
        if merchant:
            info['merchant_id'] = merchant.id
        message_info = str(statement.statement_date)[4:]
        DoctorMessage.add_message(info, message_info)


@bind_context('doctor/message/settle_statement')
def settle_statement_message(ctx, statement_id):
    """
    对账单结算发消息
    :param statement_id:
    :param ctx:
    :return:
    """
    statement = StatementAll.objects.get(id=statement_id)
    merchant = get_merchant(statement.doctor.id)
    info = {
        'type': DOCTOR_MESSAGE_TYPE.STATEMENT_SETTLE,
        'info_id': statement.id,
        'doctor_id': statement.doctor.id,
    }
    if merchant:
        info['merchant_id'] = merchant.id
    message_info = str(statement.statement_date)[4:]
    DoctorMessage.add_message(info, message_info)


@bind_context('doctor/message/statement_fail')
def fail_statement_message(ctx, statement_id):
    """
    对账单打款失败发消息
    :param statement_id:
    :param ctx:
    :return:
    """
    statement = StatementAll.objects.get(id=statement_id)
    merchant = get_merchant(statement.doctor.id)
    info = {
        'type': DOCTOR_MESSAGE_TYPE.STATEMENT_FAIL,
        'info_id': statement.id,
        'doctor_id': statement.doctor.id,
    }
    if merchant:
        info['merchant_id'] = merchant.id
    message_info = str(statement.statement_date)[4:]
    record = StatementAllOperation.objects.filter(statementall_id=statement_id,
                                                  optype__in=[STATEMENT_OPERATION_TYPE.BANK_DEFEAT,
                                                              STATEMENT_OPERATION_TYPE.NAME_DEFEAT]
                                                  ).order_by('id').last()
    DoctorMessage.add_message(info, message_info, STATEMENT_OPERATION_TYPE.getDesc(record.optype))


@bind_context('doctor/message/service_review')
def service_review(ctx, serviceregister_id, is_pass, reason=None):
    """
    美购审核审核提醒
    :param serviceregister_id:
    :param is_pass:
    :param ctx:
    :return:
    """
    serviceregister = ServiceRegister.objects.get(id=serviceregister_id)
    merchant = get_merchant(serviceregister.doctor.id)
    info = {
        'type': DOCTOR_MESSAGE_TYPE.SERVICE_ONLINE if is_pass else DOCTOR_MESSAGE_TYPE.SERVICE_REFUSE,
        'info_id': serviceregister.id,
        'doctor_id': serviceregister.doctor.id,
    }
    if merchant:
        info['merchant_id'] = merchant.id
    message_info = serviceregister.name
    if is_pass:
        DoctorMessage.add_message(info, message_info)
    else:
        DoctorMessage.add_message(info, message_info, reason)


@bind_context('doctor/message/service_offline')
def service_offline(ctx, serviceregister_id, is_pass, reason=None):
    """
    美购审核审核提醒
    :param serviceregister_id:
    :param is_pass:
    :param ctx:
    :return:
    """
    serviceregister = ServiceRegister.objects.get(id=serviceregister_id)
    merchant = get_merchant(serviceregister.doctor.id)
    info = {
        'type': DOCTOR_MESSAGE_TYPE.SERVICE_OFFLINE if is_pass else DOCTOR_MESSAGE_TYPE.SERVICE_OFFLINE_REFUSE,
        'info_id': serviceregister.id,
        'doctor_id': serviceregister.doctor.id,
    }
    if merchant:
        info['merchant_id'] = merchant.id
    message_info = serviceregister.name
    if is_pass:
        DoctorMessage.add_message(info, message_info)
    else:
        DoctorMessage.add_message(info, message_info, reason)


@bind_context('doctor/message/doctor_edit')
def doctor_edit(ctx, doctor_id, is_pass, reason=None):
    """
    医生资料审核提醒
    :param reason:
    :param is_pass:
    :param ctx:
    :param doctor_id:
    :return:
    """
    doctor = Doctor.objects.get(id=doctor_id)
    merchant = get_merchant(doctor_id)
    info = {
        'type': DOCTOR_MESSAGE_TYPE.DOCTOR_EXAMINE_PASS if is_pass else DOCTOR_MESSAGE_TYPE.DOCTOR_EXAMINE_REJECT,
        'info_id': doctor.id,
        'doctor_id': doctor.id,
    }
    if merchant:
        info['merchant_id'] = merchant.id
        info['doctor_id'] = merchant.doctor.id

    message_info = doctor.name
    if is_pass:
        DoctorMessage.add_message(info, message_info)
    else:
        DoctorMessage.add_message(info,message_info,reason)