# coding=utf-8
from __future__ import absolute_import, unicode_literals

import json
import datetime

from xml.etree import ElementTree

from django.conf import settings
from django.db import transaction

from gm_types.pay.union import CHANNEL

from api.models import Order
from api.models import RefundOrder
from api.models import CashBackOrder
from api.models import REFUND_STATUS
from api.models import NEW_CASH_BACK_STATUS
from api.models import Person
from api.models import ORDER_OPERATION_TYPE
from api.models import ORDER_OPERATION_ROLE
from api.models import Settlement
from api.manager import order_manager
from api.tool.user_tool import get_user_from_context
from pay.models import PaymentOrder, PaymentOrderItem
from rpc.tool.log_tool import alipay_refund_logger, channel_logger
from api.tool.log_tool import alipay_pay_logger

from pay.tool import own_tool
from pay.tool.new_order_tool import refund_send_notification_and_sms
from pay.tool.new_order_tool import cashback_send_notification_and_sms
from pay.tool.new_order_tool import change_alipay_refund
from pay.tool.alipay_tool import alipay_refund_nopwd, new_alipay_refund_nopwd
from pay.tool.alipay_tool import check_is_from_alipay,new_check_is_from_alipay
from pay.tool.alipay_tool import AlipayAppPayTools, AlipayWapPayTools,AlipayTool
from pay.tool.types import REFUND_TYPE
from pay.tool.order_lock_tool import lock
from pay.tool.order_lock_tool import is_locked
from pay.tool.new_order_tool import get_actual_refund_amount
from pay.tool.alipay_tool import get_create_direct_pay_url
from rpc.tool.log_tool import logging_exception

from rpc.tool.error_code import gen, CODES
from rpc.decorators import bind, bind_context

from pay.models import AlipayRefund
from pay.tool.refund_tool import RefundTool
from gm_types.pay.union import REFUND_CODE


@bind('pay/alipay/refund/new')
def pay_alipay_refund(order_id):
    try:
        refund_order = RefundOrder.objects.get(order_id=order_id)
    except RefundOrder.DoesNotExist:
        logging_exception()
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS,message='订单{0}不存在'.format(order_id))

    if refund_order.status == REFUND_STATUS.REFUNDED:
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS)

    # 商户同意退款
    # 商户超时操作, 自动默认退款
    # 仲裁同意退款
    if refund_order.status not in (
            REFUND_STATUS.DOCTOR_APPROVE,
            REFUND_STATUS.REFUND_APPLY_SELLER_TIMEOUT,
            REFUND_STATUS.ARBIT_APPROVE):
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS,message='订单{0}退款状态{1}不能退款'.format(order_id,REFUND_STATUS.getDesc(refund_order.status)))

    # 退款时现算退款金额, 我是非常不赞成的
    # 最重要改成申请退款时, 就算出退款金额
    refund_order.fee = get_actual_refund_amount(refund_order.order)
    refund_order.save(update_fields=['fee'])

    payment_order = PaymentOrder.objects.get(orders=refund_order.order_id)

    code = do_refund(order_id=refund_order.id,
                     refund_fee=refund_order.fee,
                     payment_order=payment_order,
                     refund_type=REFUND_TYPE.REFUND)

    operator = Person.objects.get(user_id=settings.BOSS)
    if code == REFUND_CODE.SUCCESS:
        RefundTool.add_refund_success_order(order_id)

        with transaction.atomic():
            # 增加 double lock （？），避免并发导致的订单状态错误
            ro = RefundOrder.objects.select_for_update().get(order_id=order_id)
            if ro.status != REFUND_STATUS.REFUNDED:
                ro.order.operate(operator, ORDER_OPERATION_TYPE.REFUNDED, ORDER_OPERATION_ROLE.SYSTEM)
    elif code == REFUND_CODE.CLOSED:
        RefundTool.add_refund_success_order(order_id)
        refund_order.order.operate(operator, ORDER_OPERATION_TYPE.TAG_STALE_REFUND, ORDER_OPERATION_ROLE.SYSTEM)

    if code != REFUND_CODE.SUCCESS:
        return gen(CODES.SUCCESS, message=REFUND_CODE.getDesc(code))

    try:
        po = PaymentOrder.objects.get(channel=CHANNEL.ALIPAY, transaction_id=payment_order.transaction_id)
        order_ids = set(PaymentOrderItem.objects.filter(payment_order_id=po.id).values_list('order_id', flat=True))

        if str(order_id) in order_ids:

            order = Order.objects.get(id=str(order_id))

            from api.tool.order_tool import send_momo_stat_log_info_when_order_refunded
            send_momo_stat_log_info_when_order_refunded(order)

            order_manager.send_order_refunded_event(order)
            refund_send_notification_and_sms(order)

    except:
        logging_exception()

    return gen(CODES.SUCCESS)



def do_refund(order_id,refund_fee,payment_order,refund_type):

    alipay_notify_data = json.loads(payment_order.notify_data)
    seller_id = alipay_notify_data.get('seller_id')

    refund_reason = '协商退款'
    if refund_type == REFUND_TYPE.CASHBACK:
        refund_reason = '日记返现'

    out_request_no = '{0}{1}'.format(order_id,refund_type)
    code,r = AlipayTool.refund(pid=seller_id,
                          trade_no=payment_order.transaction_id,
                          refund_amount=refund_fee,
                          refund_reason=refund_reason,
                          out_request_no=out_request_no,
                          operator_id=ORDER_OPERATION_ROLE.SYSTEM)

    if code == REFUND_CODE.SUCCESS:
        RefundTool.add_refund_success_order(order_id)
        if r.get('fund_change') == 'Y':
            AlipayRefund.objects.create(order_no=order_id,
                                        refund_fee=refund_fee,
                                        trade_no=r.get('trade_no'),
                                        batch_no=out_request_no,
                                        trade_status="success",
                                        notify_id=REFUND_CODE.SUCCESS)
    else:
        AlipayRefund.objects.create(order_no=order_id,
                                    refund_fee=refund_fee,
                                    trade_no='none',
                                    batch_no=out_request_no,
                                    trade_status=r.get('sub_msg'),
                                    notify_id=REFUND_CODE.FAIL)
    return code


def retry_do_refund(order_id):
    from rpc.context import create_fake_context
    ctx = create_fake_context()
    ctx.gaia_local['pay/alipay/refund/new'](order_id=order_id).unwrap()


def retry_do_cashback(order_id):
    from rpc.context import create_fake_context
    ctx = create_fake_context()
    ctx.gaia_local['pay/alipay/cashback/new'](order_id=order_id).unwrap()


@bind('pay/alipay/cashback/new')
def pay_alipay_callback(order_id):
    try:
        cashback_order = CashBackOrder.objects.get(order_id=order_id)
    except CashBackOrder.DoesNotExist:
        logging_exception()
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS, message='订单{0}不存在'.format(order_id))

    if cashback_order.status == NEW_CASH_BACK_STATUS.SUCCESS:
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS, message='订单{0}已经成功返现'.format(order_id))

    if cashback_order.status != NEW_CASH_BACK_STATUS.WAIT:
        RefundTool.add_refund_success_order(order_id)
        return gen(CODES.SUCCESS, message='订单{0}返现状态{1}不能返现'.format(order_id, NEW_CASH_BACK_STATUS.getDesc(cashback_order.status)))

    payment_order = PaymentOrder.objects.get(orders=order_id)

    code = do_refund(order_id=cashback_order.id,
                     refund_fee=cashback_order.fee,
                     payment_order=payment_order,
                     refund_type=REFUND_TYPE.CASHBACK)

    operator = Person.objects.get(user_id=settings.BOSS)
    if code == REFUND_CODE.SUCCESS:
        RefundTool.add_refund_success_order(order_id)
        with transaction.atomic():
            # 增加 double lock （？），避免并发导致的订单状态错误
            cbo = CashBackOrder.objects.select_for_update().get(order_id=order_id)
            if cbo.status != NEW_CASH_BACK_STATUS.SUCCESS:
                cbo.order.operate(operator, ORDER_OPERATION_TYPE.CASHBACKED, ORDER_OPERATION_ROLE.SYSTEM)

    elif code == REFUND_CODE.CLOSED:
        RefundTool.add_refund_success_order(order_id)
        cashback_order.order.operate(operator, ORDER_OPERATION_TYPE.TAG_STALE_CASHBACK, ORDER_OPERATION_ROLE.SYSTEM)

    if code != REFUND_CODE.SUCCESS:
        return gen(CODES.SUCCESS, message=REFUND_CODE.getDesc(code))

    try:
        po = PaymentOrder.objects.get(channel=CHANNEL.ALIPAY, transaction_id=payment_order.transaction_id)
        order_ids = set(PaymentOrderItem.objects.filter(payment_order_id=po.id).values_list('order_id', flat=True))

        if str(order_id) in order_ids:
            order = Order.objects.get(id=str(order_id))
            cashback_send_notification_and_sms(order)
    except:
        logging_exception()

    return gen(CODES.SUCCESS, message=REFUND_CODE.getDesc(code))


@bind_context('pay/alipay/create_direct_pay', login_required=True)
def alipay_create_direct_pay(ctx, settlement_id, subject, callback_url):
    user = get_user_from_context(ctx)
    alipay_pay_logger.info("settlement_id: %s, callback_url: %s" %(settlement_id, callback_url))
    settlement = own_tool.is_my_settlement(user, settlement_id)

    url = AlipayTool.gen_direct_pay_url(
        pid=settings.ALIPAY_USING_PARTNER,
        subject=settlement.name,
        out_trade_no=settlement_id,
        total_amount=settlement.real_payment,
        callback_url=callback_url,
    )

    alipay_pay_logger.info("redirect_url: %s" % url)
    return {'redirect_url': url}


@bind_context('pay/alipay/prepay', login_required=True)
def pay_alipay_prepay(ctx, settlement_id, version, ip, is_huabei=False, huabei_period=0):
    """
    支付请求参数参考
        https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.WlyfbF&treeId=193&articleId=105465&docType=1
    """
    alipay_pay_logger.info("pay/alipay/prepay： settlement_id=%s, ip=%s, is_huabei=%s, period=%s", settlement_id, ip, is_huabei, huabei_period)
    user = get_user_from_context(ctx)

    settlement = own_tool.is_my_settlement(user, settlement_id)

    biz_content = {
                    "out_trade_no": settlement_id,
                    "subject": settlement.name[:256],
                    "body": settlement.name[:128],
                    "total_amount": settlement.real_payment,
    }

    order_info = AlipayTool.api_alipay_trade_app_pay(pid=settings.ALIPAY_USING_PARTNER,
                                                     out_trade_no=settlement_id,
                                                     subject=biz_content["subject"],
                                                     body=biz_content["body"],
                                                     total_amount=biz_content["total_amount"],
                                                     is_huabei=is_huabei,
                                                     huabei_period=huabei_period)

    return order_info


