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

import datetime
from datetime import timedelta
from django.db.models import Q
from django.db import transaction
from django.conf import settings
from gm_types.gaia import NOTIFY_EVENT, NOTIFY_OPERATION
from services.notify import notify
from api.models import RefundOrder, REFUND_STATUS, DOCTOR_REFUND_TYPE, ORDER_OPERATION_TYPE, ORDER_OPERATION_ROLE, \
    ServiceItemPrice, ServiceItem
from api.tool.user_tool import get_doctor_from_context
from rpc.decorators import bind_context
from rpc.decorators import list_interface
from rpc.tool.error_code import CODES, gen
from services.doctor_notify_service import DoctorNotifyService


def _get_refund_type(refund):
    status = refund.status
    refund_type = None
    if status == REFUND_STATUS.PROCESSING:
        time_limit = datetime.datetime.now() - timedelta(hours=settings.DOCTOR_HANDLE_TIME)
        if refund.lastest_apply_refund and time_limit > refund.lastest_apply_refund:
            # 过了48个小时，则是自动退款
            refund_type = DOCTOR_REFUND_TYPE.REFUNDED
        else:
            refund_type = DOCTOR_REFUND_TYPE.PROCESSING
    elif status in [REFUND_STATUS.ARBIT_APPROVE, REFUND_STATUS.DOCTOR_APPROVE, REFUND_STATUS.REFUNDED]:
        refund_type = DOCTOR_REFUND_TYPE.REFUNDED
    elif status in [REFUND_STATUS.DOCTOR_REJECT, REFUND_STATUS.ARBITING, REFUND_STATUS.ARBIT_REJECT]:
        refund_type = DOCTOR_REFUND_TYPE.REJECT
    return refund_type


def _query_refund(doctor_ids=[], refund_type=None, filters={}):
    query = Q(order__service__doctor_id__in=doctor_ids)
    order_by = '-updated_at'
    if refund_type is None:
        # 为None时，刷选以下所有结果的并集
        query &= Q(
            status__in=[
                REFUND_STATUS.PROCESSING,
                REFUND_STATUS.ARBIT_APPROVE, REFUND_STATUS.DOCTOR_APPROVE, REFUND_STATUS.REFUNDED,
                REFUND_STATUS.DOCTOR_REJECT, REFUND_STATUS.ARBITING, REFUND_STATUS.ARBIT_REJECT
            ])
    elif refund_type == DOCTOR_REFUND_TYPE.PROCESSING:
        query &= Q(status=REFUND_STATUS.PROCESSING)
        # 医生只能处理48小时之内的
        time_limit = datetime.datetime.now() - timedelta(hours=settings.DOCTOR_HANDLE_TIME)
        query &= Q(
            lastest_apply_refund__gte=time_limit,
        )
        order_by = 'lastest_apply_refund'

    elif refund_type == DOCTOR_REFUND_TYPE.REFUNDED:
        # 经与产品经理协商, 过滤条件加上,医生同意退款状态.
        # 避免出现医生同意退款, 而第三方支付失败 导致退款单消失情况.
        query &= Q(
            status__in=[REFUND_STATUS.ARBIT_APPROVE, REFUND_STATUS.DOCTOR_APPROVE, REFUND_STATUS.REFUNDED]
        )
        order_by = '-updated_at'
    elif refund_type == DOCTOR_REFUND_TYPE.REJECT:
        query &= Q(
            status__in=[REFUND_STATUS.DOCTOR_REJECT, REFUND_STATUS.ARBITING, REFUND_STATUS.ARBIT_REJECT]
        )
        order_by = '-updated_at'
    elif refund_type == DOCTOR_REFUND_TYPE.REFUNDING:
        query &= Q(
            status__in=[REFUND_STATUS.REFUND_APPLY_SELLER_TIMEOUT,
                        REFUND_STATUS.DOCTOR_APPROVE,
                        REFUND_STATUS.REFUNDING]
        )
        order_by = '-updated_at'

    order_created_time_start = filters.pop('order_created_time_start', 0)
    order_created_time_end = filters.pop('order_created_time_end', 0)
    created_at_start = filters.pop('created_at_start', 0)
    created_at_end = filters.pop('created_at_end', 0)

    def get_timestamp(time):
        return datetime.datetime.fromtimestamp(time)

    if order_created_time_start and order_created_time_end:
        query &= Q(order__created_time__range=(get_timestamp(order_created_time_start), get_timestamp(order_created_time_end)))
    elif order_created_time_start:
        query &= Q(order__created_time__gt=get_timestamp(order_created_time_start))
    elif order_created_time_end:
        query &= Q(order__created_time__lt=get_timestamp(order_created_time_end))

    if created_at_start and created_at_end:
        query &= Q(created_at__range=(get_timestamp(created_at_start), get_timestamp(created_at_end)))
    elif created_at_start:
        query &= Q(created_at__gt=get_timestamp(created_at_start))
    elif created_at_end:
        query &= Q(created_at__lt=get_timestamp(created_at_end))

    search_q = Q()
    for k, v in filters.iteritems():
        search_q |= Q(**{k: v})

    query &= search_q
    refund_orders = RefundOrder.objects.filter(query).order_by(order_by)
    return refund_orders


@bind_context('doctor/refund/list', login_required=True)
@list_interface(offset_name='start_num', limit_name='count', element_model=RefundOrder)
def order_refund_list(ctx, doctor_ids, start_num=0, count=10, refund_type=None, filters={}):
    doctor = get_doctor_from_context(ctx)
    refund_orders = _query_refund(doctor_ids, refund_type, filters=filters)
    result = {
        'total': refund_orders.count(),
    }
    result['data'] = []
    for refund in refund_orders[start_num:start_num + count]:
        item = refund.data
        if refund_type is not None:
            item['refund_type'] = refund_type
        else:
            item['refund_type'] = _get_refund_type(refund)
        result['data'].append(item)
    return result


@bind_context('doctor/refund/statistics', login_required=True)
def refund_stat(ctx, doctor_ids, refund_type=None):
    """
        统计 待处理、已拒绝、已退款 的数目
    """
    doctor = get_doctor_from_context(ctx)
    result = {}
    if refund_type is None or refund_type == DOCTOR_REFUND_TYPE.PROCESSING:
        result['processing'] = _query_refund(doctor_ids, DOCTOR_REFUND_TYPE.PROCESSING).count()
    if refund_type is None or refund_type == DOCTOR_REFUND_TYPE.REFUNDED:
        result['refunded'] = _query_refund(doctor_ids, DOCTOR_REFUND_TYPE.REFUNDED).count()
    if refund_type is None or refund_type == DOCTOR_REFUND_TYPE.REJECT:
        result['reject'] = _query_refund(doctor_ids, DOCTOR_REFUND_TYPE.REJECT).count()
    return result


@bind_context('doctor/refund/detail', login_required=True)
def refund_detail(ctx, refund_id):
    try:
        refund_order = RefundOrder.objects.select_related('order__service__doctor').get(id=refund_id)
    except RefundOrder.DoesNotExist:
        return gen(CODES.REFUND_ORDER_NOT_FOUND)

    # 暂时去掉检查
    '''
    if refund_order.order.service.doctor != doctor:
        return gen(CODES.NO_PERMISSION)
    '''
    data = refund_order.data
    data.update(refund_timeline=refund_order.refund_timeline)
    data['refund_type'] = _get_refund_type(refund_order)

    order = refund_order.order
    is_multibuy = True if order.service_item_id and ServiceItem.objects.get(id=order.service_item_id).parent_id else False
    data.update(is_multibuy=is_multibuy)
    data.update({
        'is_doctor_see': order.is_doctor_see,
        'customer_phone': None,
    })
    if order.is_doctor_see:
        data['customer_phone'] = order.phone
    return data


@bind_context('doctor/refund/approve', login_required=True)
def doctor_order_approve_refund(ctx, refund_order_id):
    doctor = get_doctor_from_context(ctx)
    try:
        refund = RefundOrder.objects.get(pk=refund_order_id)
    except RefundOrder.DoesNotExist:
        raise gen(CODES.ORDER_CAN_NOT_REFUND)
    from hippo.models.merchant import *
    try:
        m_doctor = MerchantRelevance.objects.get(doctor_id=doctor.id).merchant.doctor
    except MerchantRelevance.DoesNotExist:
        m_doctor = None
    if refund.order.service.doctor != doctor and m_doctor != doctor:
        raise gen(CODES.NO_PERMISSION)

    refund.order.operate(doctor.user.person, ORDER_OPERATION_TYPE.DOCTOR_APPROVE, ORDER_OPERATION_ROLE.DOCTOR)
    refund.doctor = doctor
    refund.save()

    ss = DoctorNotifyService.get_service(doctor.id)
    ss.notify_confirm_refund(refund)

    try:
        ctx.gaia_local['pay/unified/refund'](order_id=refund.order_id).unwrap()
    except:
        # 正常情况下, 医生退款, 肯定能退.
        # 如果不能, 则为异常情况
        # 异常情况, 不可干扰医生退款流程.
        pass

    # add 医生版实时小红点数量
    notify("refund/delete", doctor_id=doctor.id)


@bind_context('doctor/refund/query')
def refund_list(ctx, start_num=0, count=10, query={}, global_field=[], global_key='', order_by=[]):
    q = Q(**query)
    doctor = get_doctor_from_context(ctx)
    q &= Q(doctor=doctor)
    if global_key:
        global_q = Q()
        for field in global_field:
            global_q |= Q(**{field: global_key})
        q &= global_q
    orders = RefundOrder.objects.filter(q)
    orders = orders.order_by(*order_by)
    total = orders.count()
    orders = orders[start_num: start_num + count]
    return {
        'total': total,
        'orders': [order.data for order in orders],
    }
