# coding=utf-8
from __future__ import absolute_import

import random
import datetime
from time import sleep
import calendar
import time
import sys
from celery import shared_task
from django.db import transaction
from django.conf import settings
from django.utils import timezone

from gm_types.gaia import SERVICE_SELL_TYPE, PLATFORM_CHOICES,BWC_ORDER_NOTIFY_METHOD
from gm_types.push import PUSH_INFO_TYPE,AUTOMATED_PUSH,J_TYPE,PUSH_URGENCY
from gm_protocol import GmProtocol

from api.models import Doctor, DoctorCountRecord, Q, OrderUserInfo
from api.models.order import Order, ORDER_STATUS_USED, OrderExtra, BWCOrderVerifyNotice
from api.models.user import User
from api.models.order import RefundOrder
from api.models.order import REFUND_STATUS
from api.models.types import ORDER_STATUS
from api.models.types import PAYMENT_TYPE
from api.models.types import ORDER_OPERATION_TYPE
from api.models.types import ORDER_OPERATION_ROLE
from api.tool.log_tool import logging_exception
from api.manager.refund_manager import increase_inventory, decrease_inventory

from statistic import const_strings
from rpc.all import get_rpc_remote_invoker
from rpc.cache import ViewRecord, doctor_discount_cache
from rpc.tool.error_code import CODES, gen

from services.talos_service import get_order_has_diary_and_topics
from talos.tools.push_tool import special_push_limit
from talos.libs.protocol import gm_protocol
from rpc.tool.log_tool import info_logger
import json
from helios import RPCSystemException, RPCFaultException
import traceback

@shared_task
def order_increase_event(order_id):
    try:
        order = Order.objects.get(pk=order_id)
        service = order.service
        view = ViewRecord(const_strings.SERVICE)
        show_volume = int(view[service.id] or '0')

        up = 10
        if service.get_service_type == const_strings.EXCHANGE_GIFT:
            up = 5

        if service.id in settings.GROUPON_SERVICE_IDS:
            up = 1

        add = random.randint(1, up)

        if service.service_type == SERVICE_SELL_TYPE.ONEPURCHASE:
            add = 0

        view[service.id] = show_volume + add

    except Order.DoesNotExist:
        logging_exception()


@shared_task
def order_event_for_apollo(event_message):
    rpc_invoker = get_rpc_remote_invoker()

    retry_count = 0

    while retry_count < 3:
        try:
            rpc_invoker['apollo/gaia/proccess_event'](
                event_message=event_message
            ).unwrap()

            break
        except Exception as e:
            retry_count += 1
            print(e)
            logging_exception()
            sleep(retry_count * 2)

# @shared_task
# def order_create_event(order_id, remind_before_expire=True, timeout_cancel=True):
#     try:
#         order = Order.objects.get(pk=order_id)
#
#         if timeout_cancel:
#             delta = datetime.timedelta(seconds=settings.ORDER_TIMEOUT)
#             order.expired_date = datetime.datetime.now() + delta
#             order.save()
#             order_timeout_event.apply_async((order_id,), countdown=settings.ORDER_TIMEOUT)
#
#         if remind_before_expire:
#             remind_countdown = settings.ORDER_TIMEOUT - settings.REMIND_TIME_BEFORE_ORDER_EXPIRED
#             order_expired_reminder.apply_async((order_id,), countdown=remind_countdown)
#
#         return True
#
#     except Order.DoesNotExist:
#         logging_exception()
#
#     return False


@shared_task
def set_order_is_read_by_order_ids(order_ids):
    """
        异步更新订单已读状态，避免订单表死锁
    :param order_id:
    :return:
    """

    # 这里是特意一行一行处理，减少不可预期的死锁状态
    for oid in order_ids:
        Order.objects.filter(id=oid).update(read=True)


@shared_task
def remind_user_write_diary_after_order_validate(order_id):
    """
    改为5小时推送
    :param order_id:
    :return:
    """
    push_remind_if_user_has_not_write_diary.apply_async(
        args=(order_id,),
        countdown=datetime.timedelta(hours=5).seconds
    )


@shared_task
def push_remind_if_user_has_not_write_diary(order_id):
    o = list(Order.objects.filter(id=order_id).values_list('id', 'user_id'))
    if len(o) == 1:
        order_id, user_id, = o[0]

        diary_has_topics = get_order_has_diary_and_topics(order_id)

        user_has_not_write_diary = not diary_has_topics

        if user_has_not_write_diary and special_push_limit(user_id, "verify_write_diary"):
            gm_protocol = GmProtocol()
            extra = {
                'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                'pushUrl': gm_protocol.get_select_diary(),
            }

            content = (
                u'听说你变美啦！' +
                u'如果美人在社区发发照片分享术后心得就有机会赢得返现哦！' +
                u'具体详情可以私信返现小助手咨询哦！'
            )

            platform = [PLATFORM_CHOICES.ANDROID, PLATFORM_CHOICES.IPHONE]
            kwargs = {
                'platform': platform,
                'user_id': user_id,
                'extra': extra,
                'alert': content,
            }
            from api.tasks.push_task import allocate_push_task_one
            allocate_push_task_one(**kwargs)


@shared_task
def order_expired_reminder(order_id):
    try:
        order = Order.objects.get(pk=order_id)
        if order.service.payment_type == PAYMENT_TYPE.FREE_PAYMENT:
            return

        time_left = settings.REMIND_TIME_BEFORE_ORDER_EXPIRED
        if order.status == ORDER_STATUS.NOT_PAID:
            from api.tool.order_tool import send_order_expired_remind
            send_order_expired_remind(order.phone, order.id, order.service.name, order.user.id, time_left)
    except Order.DoesNotExist:
        logging_exception()


# @shared_task
# def order_timeout_event(order_id):
#    try:
#        order = Order.objects.get(pk=order_id)
#        if order.status == ORDER_STATUS.NOT_PAID:
#            # 返还美券
#            from api.tool.coupon_tool import return_coupon
#
#            return_coupon(order.id)
#            order_cancel_event.delay(order.id)
#    except Order.DoesNotExist:
#        logging_exception()
# @shared_task
# def order_timeout_event(order_id):
#     try:
#         order = Order.objects.get(pk=order_id)
#         if order.status == ORDER_STATUS.NOT_PAID:
#             # 返还美券
#             from api.manager.coupon_manager import return_coupon
#
#             return_coupon(order.id)
#             order_cancel_event.delay(order.id)
#     except Order.DoesNotExist:
#         logging_exception()


@shared_task
def order_decrease_event(order_id):
    pass


@shared_task
def refund_cancle_event(order_id):
    try:
        with transaction.atomic():
            order = Order.objects.get(pk=order_id)
            decrease_inventory(order)

    except Order.DoesNotExist:
        logging_exception()


@shared_task
def doctor_refund_timeout():
    from api.tool.log_tool import doctor_unread_logger
    from datetime import datetime, timedelta
    from services.notify import notify
    time_threshold = datetime.now() - timedelta(minutes=settings.DOCTOR_REFUND_TIMEOUT_MINUTES)
    refund_orders = RefundOrder.objects.filter(
        status=REFUND_STATUS.PROCESSING,
        lastest_apply_refund__lt=time_threshold)
    system_user = User.objects.get(pk=settings.BOSS)
    operator = system_user.person
    from rpc.context import create_fake_context
    ctx = create_fake_context()
    for refund_order in refund_orders:
        check_status = RefundOrder.objects.filter(
            status=REFUND_STATUS.PROCESSING, order_id=refund_order.order_id,
        )
        if not check_status.exists():
            continue
        try:
            refund_order.order.operate(operator, ORDER_OPERATION_TYPE.REFUND_TIMEOUT, ORDER_OPERATION_ROLE.SYSTEM)
            ctx.gaia_local['pay/unified/refund'](order_id=refund_order.order.id).unwrap()
        except:
            logging_exception()
        # add 医生版实时小红点数量
        doctor_id = refund_order.order.service.doctor.id
        doctor_unread_logger.info("doctor_refund_timeout, doctor id:{}, refund_order_id:{}".format(
            doctor_id, refund_order.id))
        notify("refund/delete", doctor_id=doctor_id)


@shared_task
def speed_refund(refund):
    from rpc.context import create_fake_context
    ctx = create_fake_context()
    try:
        ctx.gaia_local['pay/unified/refund'](
            order_id=refund.order.id).unwrap()
    except:
        pass


@shared_task
def start_refund(refund_order_id):
    from rpc.context import create_fake_context
    ctx = create_fake_context()
    try:
        ctx.gaia_local['pay/unified/refund'](
            order_id=refund_order_id).unwrap()
    except:
        logging_exception()


# 只会执行一次 在command里面调用
@shared_task
def calc_doctor_discount_all():
    doctors = Doctor.objects.all()
    max_money = 0
    min_money = sys.maxsize
    for doctor in doctors:
        orders = Order.objects.filter(service__doctor=doctor, status__in=ORDER_STATUS_USED)
        all_money = 0
        for o in orders:
            all_money += o.discount
        try:
            d = DoctorCountRecord.objects.get_or_create(doctor=doctor)
            d[0].discount = all_money
            print (doctor.id + ' ' + str(all_money))
            d[0].save()
            if max_money < all_money:
                max_money = all_money
            if min_money > all_money:
                min_money = all_money
        except:
            logging_exception()

    # 防止最大值为0
    if max_money == 0:
        max_money = 1

    dcs = DoctorCountRecord.objects.all()
    for dc in dcs:
        doctor_discount_cache.set('doctor:' + dc.doctor_id, (dc.discount-min_money)*100/(max_money-min_money))


@shared_task
def calc_doctor_discount_one_day():
    doctors = Doctor.objects.all()
    now = timezone.now()
    t = now - datetime.timedelta(days=1)
    max_money = 0
    min_money = sys.maxsize
    one_day_before = datetime.datetime(
        year=t.year,
        month=t.month,
        day=t.day,
        hour=0,
        minute=0,
        second=0
    )
    now = datetime.datetime(
        year=now.year,
        month=now.month,
        day=now.day,
        hour=0,
        minute=0,
        second=0
    )
    for doctor in doctors:
        q = Q(last_modified__range=(one_day_before, now)) & Q(status__in=ORDER_STATUS_USED)
        q &= Q(service__doctor=doctor)
        orders = Order.objects.filter(q)
        all_money = 0
        for order in orders:
            all_money += order.discount
        try:
            d = DoctorCountRecord.objects.get_or_create(doctor=doctor)
            d[0].discount += all_money
            print (doctor.id + ' ' + str(all_money))
            d[0].save()
            if max_money < d[0].discount:
                max_money = d[0].discount
            if min_money > d[0].discount:
                min_money = d[0].discount
        except:
            logging_exception()

    # 防止最大值为0
    if max_money == 0:
        max_money = 1
    dcs = DoctorCountRecord.objects.all()
    for dc in dcs:
        doctor_discount_cache.set('doctor:' + dc.doctor_id, (dc.discount-min_money)*100/(max_money-min_money))


@shared_task
def record_user_information(orders, hospitalpay_id, device_id, ip, status):
    # 记录用户的设备标识,ip
    OrderUserInfo.objects.bulk_create([
        OrderUserInfo(
            order_id=order.id,
            hospitalpay_id=hospitalpay_id,
            status=status,
            device_id=device_id,
            ip=ip,
        )
        for order in orders
    ])


@shared_task
def auto_push_bwc_order_not_verify():
    """
    霸王餐订单未验证推送
    """
    rpc_invoker = get_rpc_remote_invoker()
    currentdate = datetime.date.today()
    year = currentdate.year
    month = currentdate.month
    day = currentdate.day
    currentday = calendar.weekday(year, month, day)

    bulk_create_list = []

    # 三天前日期
    three_day_ago = currentdate - datetime.timedelta(days=3)
    # 霸王餐订单id列表
    bwc_order_id_list = OrderExtra.objects.filter(promotion_type='霸王餐').values_list('order',flat=True)
    if bwc_order_id_list:
        # 为了防止下面订单第三天发送策略不重复
        friday_bwc_order_2_user_map = {}
        # 如果是周五
        if currentday == 4:
            # 执行策略2
            # 霸王餐节假日未验证的订单列表(id, user_id)
            bwc_order_not_verify_5_list = Order.objects.filter(
                id__in=bwc_order_id_list,
                status=ORDER_STATUS.PAID).values_list('id', 'user')
            friday_bwc_order_2_user_map = {order_id: user_id for order_id, user_id in bwc_order_not_verify_5_list}
            if bwc_order_not_verify_5_list:
                # 查看是否已经发送过节假日推送了
                have_send_order_list = BWCOrderVerifyNotice.objects.filter(
                    order_id__in=list(friday_bwc_order_2_user_map.keys()),
                    send_method=BWC_ORDER_NOTIFY_METHOD.FRIDAY).values_list('order', flat=True)
                if have_send_order_list:
                    for order_id in have_send_order_list:
                        if order_id in friday_bwc_order_2_user_map:
                            friday_bwc_order_2_user_map.pop(order_id)
                if friday_bwc_order_2_user_map:
                    # 如果还有剩余的节假日发送的订单，需要发送策略2推送
                    B_title = u'🔔免单福利！即将过期❗'
                    B_subtitle = u'🌼您下单的新人免单项目还未体验，0恢复期，逛街聚会不耽误，祝你美美享受假期！💃现在预约吧！'
                    for order_id in friday_bwc_order_2_user_map:
                        user_id = friday_bwc_order_2_user_map[order_id]
                        # if getattr(settings, 'BWC_PUSH_USER_WHITE') and user_id not in settings.BWC_PUSH_USER_WHITE:
                        #     continue
                        if user_id:
                            push_url = gm_protocol.get_order_detail(id=order_id)
                            extra = {
                                'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                                'msgType': PUSH_INFO_TYPE.GM_PROTOCOL,
                                'pushUrl': push_url,
                                'push_url': push_url,
                            }
                            kwargs = {
                                'user_ids': [user_id],
                                'push_type': AUTOMATED_PUSH.UNVERIFIED_US_PURCHASER,
                                'platform': [PLATFORM_CHOICES.ANDROID, PLATFORM_CHOICES.IPHONE],
                                'alert': B_subtitle,
                                'push_time': int(time.time()),
                                'silent': False,
                                'urgency': PUSH_URGENCY.URGENT,
                                'j_type': J_TYPE.NOTIFICATION,
                                'extra': extra,
                                'others': {'title': B_title, 'alert': B_subtitle}

                            }
                            try:
                                message = rpc_invoker['push2/push/user/automated_push/uids'](**kwargs).unwrap() or {}

                                if message:
                                    info_logger.info(
                                        '霸王餐周五未验证推送success---msg_id--{}---order_id---{}---user_id---{}'.format(
                                            message.get('msg_id', ''), order_id, user_id))
                                    order_verify_notice_dict = {
                                        'order_id': order_id,
                                        'user_id': user_id,
                                        'msg_id': message.get('msg_id', ''),
                                        'title': B_title,
                                        'alert': B_subtitle,
                                        'send_method': BWC_ORDER_NOTIFY_METHOD.FRIDAY,
                                        'push_param': json.dumps(kwargs)
                                    }
                                    info_logger.info(order_verify_notice_dict)
                                    obj = BWCOrderVerifyNotice(order_id=order_id, user_id=user_id,
                                                               msg_id=message.get('msg_id', ''), title=B_title,
                                                               alert=B_subtitle, push_param=json.dumps(kwargs),
                                                               send_method=BWC_ORDER_NOTIFY_METHOD.FRIDAY)
                                    bulk_create_list.append(obj)

                                else:
                                    info_logger.info(
                                        '霸王餐周五未验证推送fail---message---{}---order_id---{}---user_id---{}'.format(
                                            str(message), order_id, user_id))
                            except (RPCFaultException, RPCSystemException) as e:
                                info_logger.info(traceback.format_exc())
                                info_logger.info(
                                    '霸王餐周五未验证推送fail---order_id---{}---user_id---{}'.format(order_id, user_id))
        # 霸王餐3天还未验证的订单列表(id, user_id) 除去上一步中周五发送的订单
        bwc_order_not_verify_3_list = Order.objects.filter(id__in=list(set(bwc_order_id_list)-set(friday_bwc_order_2_user_map.keys())), status=ORDER_STATUS.PAID,
                                          pay_time__gte=three_day_ago, pay_time__lt=three_day_ago+datetime.timedelta(days=1)).values_list('id', 'user')
        three_day_bwc_order_2_user_map = {order_id: user_id for order_id, user_id in bwc_order_not_verify_3_list}
        if bwc_order_not_verify_3_list:
            # 查看到达3天中的订单是否已经发过通知了
            have_send_order_list = BWCOrderVerifyNotice.objects.filter(order_id__in=list(three_day_bwc_order_2_user_map.keys())).values_list('order',flat=True)
            if have_send_order_list:
                for order_id in have_send_order_list:
                    if order_id in three_day_bwc_order_2_user_map:
                        three_day_bwc_order_2_user_map.pop(order_id)

            if three_day_bwc_order_2_user_map:
                # 如果还有剩余的支付后第三天的订单，需要发送策略一推送
                A_title = u'🧚你的免单项目还未体验哦'
                A_subtitle = u'👒医美第一步，无创极速变美，过期失效啦！心动不如行动，戳我即刻预约！📩'
                for order_id in three_day_bwc_order_2_user_map:
                    user_id = three_day_bwc_order_2_user_map[order_id]
                    # if getattr(settings, 'BWC_PUSH_USER_WHITE') and user_id not in settings.BWC_PUSH_USER_WHITE:
                    #     continue
                    if user_id:
                        push_url = gm_protocol.get_order_detail(id=order_id)
                        extra = {
                            'type': PUSH_INFO_TYPE.GM_PROTOCOL,
                            'msgType': PUSH_INFO_TYPE.GM_PROTOCOL,
                            'pushUrl': push_url,
                            'push_url': push_url,
                        }
                        kwargs = {
                            'user_ids':[user_id],
                            'push_type':AUTOMATED_PUSH.UNVERIFIED_US_PURCHASER,
                            'platform':[PLATFORM_CHOICES.ANDROID, PLATFORM_CHOICES.IPHONE],
                            'alert':A_subtitle,
                            'push_time':int(time.time()),
                            'extra':extra,
                            'silent':False,
                            'urgency':PUSH_URGENCY.URGENT,
                            'j_type':J_TYPE.NOTIFICATION,
                            'others':{'title':A_title,'alert':A_subtitle}
                        }
                        try:
                            message = rpc_invoker['push2/push/user/automated_push/uids'](**kwargs).unwrap() or {}

                            if message:
                                info_logger.info('霸王餐第三天未验证推送success---msg_id--{}---order_id---{}---user_id---{}'.format(message.get('msg_id',''),order_id,user_id))
                                order_verify_notice_dict = {
                                    'order_id':order_id,
                                    'user_id':user_id,
                                    'msg_id':message.get('msg_id',''),
                                    'title':A_title,
                                    'alert':A_subtitle,
                                    'push_param':json.dumps(kwargs)
                                }
                                info_logger.info(order_verify_notice_dict)
                                obj = BWCOrderVerifyNotice(order_id=order_id, user_id=user_id, msg_id=message.get('msg_id',''),title=A_title, alert=A_subtitle,push_param=json.dumps(kwargs))
                                bulk_create_list.append(obj)
                            else:
                                info_logger.info('霸王餐第三天未验证推送fail---message---{}---order_id---{}---user_id---{}'.format(str(message),order_id, user_id))
                        except (RPCFaultException, RPCSystemException) as e:
                            info_logger.info(
                                '霸王餐第三天未验证推送fail---order_id---{}---user_id---{}'.format(order_id,
                                                                                                       user_id))
                            info_logger.info(traceback.format_exc())

        if bulk_create_list:
            try:
                print bulk_create_list
                BWCOrderVerifyNotice.objects.bulk_create(bulk_create_list)
            except:
                info_logger.info('auto_push_bwc_order_not_verify')
                info_logger.info(traceback.format_exc())
                raise