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

import datetime
import time
from django.contrib.auth.models import User
from gm_types.gaia import NOTIFY_EVENT, NOTIFY_OPERATION, DOCTOR_TYPE

from api.models import Doctor
from api.tool.user_tool import get_doctor_by_user_id
from hippo.tool.chain_hospital_tools import get_master_merchant
from rpc.all import get_rpc_remote_invoker
from rpc.cache import unread_cache
from rpc.tool.log_tool import doctor_unread_logger
from services.unread.base import BaseUnread, gen_poll_channel, gen_poll_named_channel


def noti_operation(event, operation, user_id=None, doctor_id=None, data=None):
    """
        是User的操作传值user_id
        确认是Doctor操作，传值doctor_id
        user_id和doctor_id必有一个不为空

        1. event == NOTIFY_EVENT.CONVERSATION 为私信时
            data = {
                'conversation_id': 1518193,
                'send_uid': 1938785,
                'target_uid': 602329,
                'conversation_type': 1,
            }
            注意：只处理了conversation_type == 1 的未读消息
    """
    method = "{}_{}".format(event, operation)
    unread_info = u'event_operation is {}, user_id is {}, doctor_id is {}, data is {}'.format(
        method, user_id, doctor_id, json.dumps(data) if data else ''
    )
    doctor_unread_logger.info(unread_info)
    if event == NOTIFY_EVENT.CONVERSATION:  # 若是私信是面对User的
        noti_unread = NotiUserUnread(user_id)
    else:
        noti_unread = NotiDoctorUnread(doctor_id)

    handler = getattr(noti_unread, method)
    handler(data=data)


def noti_poll(doctor_id, event, operation, content):
    noti_content = {
        'event': event,
        'operation': operation,
        'content': content,
        'send_timestamp': time.time()
    }

    text = json.dumps(noti_content)
    get_rpc_remote_invoker()['poll/named_channel/publish_text'](
        named_channel=gen_poll_channel(doctor_id),
        text=text,
    ).unwrap()


def noti_user_poll(user_id, event, operation, content):
    """发送消息通知对应的用户

    :param user_id: 用户ID
    :param event: 事件 example: conversation
    :param operation: 操作  example: add
    :param content: 数据内容
    :rtype: None
    """
    noti_content = {
        'event': event,
        'operation': operation,
        'content': content,
    }
    text = json.dumps(noti_content)
    get_rpc_remote_invoker()['poll/named_channel/publish_text'](
        named_channel=gen_poll_named_channel(str(user_id)),
        text=text,
    ).unwrap()


class _NotiUnread(BaseUnread):

    _hacked_methods = []

    def __getattribute__(self, name):

        _hacked_methods = object.__getattribute__(self, '_hacked_methods')
        if name in _hacked_methods:
            def newfunc(*args, **kwargs):
                _method = name.split('_')
                _event = _method[0]
                _operation = _method[1]
                result = self._operation(_event, _operation, *args, **kwargs)
                return result
            return newfunc
        else:
            return super(_NotiUnread, self).__getattribute__(name)

    def _operation(self, *args, **options):
        raise NotImplementedError('subclasses of _NotiUnread must provide a _operation() method')


class NotiUserUnread(_NotiUnread):

    _hacked_methods = [
        # conversation_clear 是清除某个具体conversation_id会话的未读消息
        'conversation_add', 'conversation_clear',  # 'conversation_delete',
    ]

    def __init__(self, user_id):
        self.user_id = user_id

    def _gen_user_cache_key(self, event):
        """
            !!! 用户使用此获取cache_key
            不要使用 gen_cache_key
        """
        return self.gen_cache_key(event, is_user=True)

    def _operation(self, event, operation, *args, **kwargs):
        if event == NOTIFY_EVENT.CONVERSATION:  # 私信
            # 对私信的操作，都会带参数data={'conversation_id': xxx, 'send_uid': xxx, 'target_uid': xxx}
            data = kwargs['data']
            # 统计未读数
            name, key = self.gen_conversation_key(data['conversation_id'])
            if operation == NOTIFY_OPERATION.ADD:
                unread_cache.hincrby(name, key)
            elif operation == NOTIFY_OPERATION.CLEAR:
                _unread_num = unread_cache.hdel(name, key)
                data['unread_num'] = _unread_num
            unread_cache.delete(self._gen_user_cache_key(event))
            doctor = get_doctor_by_user_id(self.user_id)
            if doctor:
                noti_poll(doctor.id, event, operation, data)
                if doctor.doctor_type == DOCTOR_TYPE.DOCTOR:
                    # 通知机构管理者
                    doctor_office = Doctor.objects.filter(
                        doctor_type=DOCTOR_TYPE.OFFICER, hospital_id=doctor.hospital.id
                    ).first()
                    if doctor_office:
                        noti_poll(doctor_office.id, event, operation, data)
                _merchant = doctor.merchant
                if _merchant:
                    # 通知商户
                    _master_merchant = get_master_merchant(_merchant)
                    if _master_merchant:
                        noti_poll(_master_merchant.doctor.id, event, operation, data)

            else:
                noti_user_poll(self.user_id, event, operation, data)


class NotiDoctorUnread(_NotiUnread):

    _hacked_methods = [
        'order_add', 'order_delete', 'order_clear',
        'refund_add', 'refund_delete',  # 'refund_clear',
        'reserve_add', 'reserve_delete',  # 'reserve_clear',
        'system_add',
        'deal_add',
    ]

    def __init__(self, doctor_id):
        self.doctor_id = doctor_id

    def _operation(self, event, operation, *args, **kwargs):
        key = self.gen_cache_key(event, *args, **kwargs)
        del_num = unread_cache.delete(key)
        unread_info = u'NotiDoctorUnread._operation, key is {}, del_num is {}'.format(key, del_num)
        doctor_unread_logger.info(unread_info)

        if event == NOTIFY_EVENT.ORDER and operation == NOTIFY_OPERATION.CLEAR:
            # 若是查看订单列表时，则清除小红点，记录查看时间
            order_time_key = self.gen_order_viewtime_key(key)
            now = datetime.datetime.now()
            unread_cache.set(order_time_key, now.strftime(self._time_fmt))
        elif event == NOTIFY_EVENT.REFUND:
            # 若是 申请退款，订单状态变成 WAIT_REFUNDED = ('6', '退款处理中')
            # 若是同意/拒绝了退款，订单状态改变了，此时需清除 更改订单的 未读统计
            order_del_num = unread_cache.delete(self.gen_cache_key(NOTIFY_EVENT.ORDER))
            order_log = u'delete order cache when operate refund, doctor_id is {}, del_num is {}'.format(
                self.doctor_id, order_del_num
            )
            doctor_unread_logger.info(order_log)

        # 通知
        noti_poll(self.doctor_id, event, operation, None)
