# 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 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
from pay.tool.alipay_tool import check_is_from_alipay
from pay.tool.alipay_tool import AlipayAppPayTools, AlipayWapPayTools
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


def _success_pre_refund_operate(trade_no, refund_amount, batch_no, notify_url):
    rsp = alipay_refund_nopwd(trade_no, refund_amount, batch_no, notify_url)
    content = rsp.text
    alipay_refund_logger.info(content)
    content = content.replace('GBK', 'utf-8')
    e = ElementTree.fromstring(content)
    is_success = e.findtext('is_success')
    if is_success == 'T':
        return True
    return False


def _succeed_refund_operate(order_id, trade_data, refund_type):
    alipay_refund_logger.info(json.dumps(trade_data))
    notify_id = trade_data['notify_id']
    is_from_alipay = check_is_from_alipay(notify_id)
    log_str = "notify_id {notify_id} is from alipay: {is_from_alipay}".format(notify_id=notify_id,
                                                                              is_from_alipay=is_from_alipay)
    if is_from_alipay:
        alipay_refund_logger.info(log_str)
    else:
        alipay_refund_logger.warning(log_str)
        return False

    trade_no, fee, trade_status = trade_data['result_details'].split('^')
    try:
        po = PaymentOrder.objects.get(channel=CHANNEL.ALIPAY, transaction_id=trade_no)
        order_ids = set(PaymentOrderItem.objects.filter(payment_order_id=po.id).values_list('order_id', flat=True))

        if str(order_id) not in order_ids:
            return gen(CODES.ORDER_NOT_FOUND)

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

    except:
        logging_exception()
        return False

    operator = Person.objects.get(user_id=settings.BOSS)

    if trade_status == 'SUCCESS':
        if refund_type == REFUND_TYPE.REFUND:
            try:
                refund_order = RefundOrder.objects.get(order=order)
            except RefundOrder.DoesNotExist:
                return gen(CODES.ORDER_NOT_FOUND)
            refund_order.order.operate(operator, ORDER_OPERATION_TYPE.REFUNDED, ORDER_OPERATION_ROLE.SYSTEM)

            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(refund_order.order)
            refund_send_notification_and_sms(order)

        if refund_type == REFUND_TYPE.CASHBACK:
            try:
                cashback_order = CashBackOrder.objects.get(order=order)
            except CashBackOrder.DoesNotExist:
                return gen(CODES.ORDER_NOT_FOUND)
            cashback_order.order.operate(operator, ORDER_OPERATION_TYPE.CASHBACKED, ORDER_OPERATION_ROLE.SYSTEM)
            cashback_send_notification_and_sms(order)

    if 'TRADE_HAS_FINISHED' == trade_status:
        if refund_type == REFUND_TYPE.REFUND:
            try:
                refund_order = RefundOrder.objects.get(order=order)
            except RefundOrder.DoesNotExist:
                return gen(CODES.ORDER_NOT_FOUND)
            refund_order.order.operate(operator, ORDER_OPERATION_TYPE.TAG_STALE_REFUND, ORDER_OPERATION_ROLE.SYSTEM)
        if refund_type == REFUND_TYPE.CASHBACK:
            try:
                cashback_order = CashBackOrder.objects.get(order=order)
            except CashBackOrder.DoesNotExist:
                return gen(CODES.ORDER_NOT_FOUND)
            cashback_order.order.operate(operator, ORDER_OPERATION_TYPE.TAG_STALE_CASHBACK, ORDER_OPERATION_ROLE.SYSTEM)

    # Recode the alipay response whether it's succeed or failed
    change_alipay_refund(order=order, alipay_data=trade_data)
    return True


@bind('pay/alipay/refund/new')
def pay_alipay_refund(order_id):
    try:
        refund_order = RefundOrder.objects.get(order_id=order_id)
    except RefundOrder.DoesNotExist:
        return gen(CODES.ORDER_NOT_FOUND)

    is_locked(order_id=order_id, refund_type=REFUND_TYPE.REFUND)

    # 商户同意退款
    # 商户超时操作, 自动默认退款
    # 仲裁同意退款
    if refund_order.status not in (
            REFUND_STATUS.DOCTOR_APPROVE,
            REFUND_STATUS.REFUND_APPLY_SELLER_TIMEOUT,
            REFUND_STATUS.ARBIT_APPROVE):
        raise gen(CODES.ORDER_REFUDN_STATUS_ERROR)

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

    new_notify_url = settings.ALIPAY_REFUND_NOTIFY_URL + '/{order_id}/new'.format(order_id=order_id)

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

    #  batch_no退款批次号，在商户系统内唯一；规格：退款日期（8位当天日期）+流水号（3~24位，不能接受“000”，但可以接受英文字母）
    batch_no = "{}{}".format(datetime.datetime.now().strftime('%Y%m%d'), refund_order.id)

    if _success_pre_refund_operate(trade_no=payment_order.transaction_id, refund_amount=refund_order.fee,
                                   batch_no=batch_no, notify_url=new_notify_url):
        lock(order_id=order_id, refund_type=REFUND_TYPE.REFUND)
        alipay_refund_logger.info("order {order_id} pre-refund success!".format(order_id=order_id))
        return gen(CODES.SUCCESS)
    return gen(CODES.REFUND_ERROR)


@bind('pay/alipay/cashback/new')
def pay_alipay_callback(order_id):
    try:
        cashback_order = CashBackOrder.objects.get(order_id=order_id)
    except CashBackOrder.DoesNotExist:
        return gen(CODES.ORDER_NOT_FOUND)

    if cashback_order.status != NEW_CASH_BACK_STATUS.WAIT:
        return gen(CODES.ORDER_CAN_NOT_REFUND)

    is_locked(order_id=order_id, refund_type=REFUND_TYPE.CASHBACK)

    new_notify_url = settings.ALIPAY_CASHBACK_NOTIFY_URL + '/{order_id}/new'.format(order_id=order_id)
    payment_order = PaymentOrder.objects.get(orders=order_id)

    #  batch_no退款批次号，在商户系统内唯一；规格：退款日期（8位当天日期）+流水号（3~24位，不能接受“000”，但可以接受英文字母）
    batch_no = "{}{}".format(datetime.datetime.now().strftime('%Y%m%d'), cashback_order.id)

    if _success_pre_refund_operate(trade_no=payment_order.transaction_id, refund_amount=cashback_order.fee,
                                   batch_no=batch_no, notify_url=new_notify_url):
        lock(order_id=order_id, refund_type=REFUND_TYPE.CASHBACK)
        return gen(CODES.SUCCESS)
    return gen(CODES.REFUND_ERROR)


@bind('pay/alipay/callback/refund/new')
def pay_alipay_callback_refund_new(order_id, trade_data):
    if _succeed_refund_operate(order_id, trade_data, REFUND_TYPE.REFUND):
        return
    else:
        return gen(CODES.REFUND_ERROR)


@bind('pay/alipay/callback/cashback/new')
def pay_alipay_callback_cashback_new(order_id, trade_data):
    if _succeed_refund_operate(order_id, trade_data, REFUND_TYPE.CASHBACK):
        return
    else:
        return gen(CODES.REFUND_ERROR)


@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 = get_create_direct_pay_url(
    #         out_trade_no=settlement_id,
    #         subject=settlement.name,
    #         total_fee=settlement.real_payment,
    #         callback_url=callback_url
    # )
    alipay = AlipayWapPayTools()
    url = alipay.gen_direct_pay_url(
        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}

_AlipayAppPayTools = {}

def _init_AlipayAppPayTools():
    tools = AlipayAppPayTools()
    tools.use_old_conifg()
    _AlipayAppPayTools["old"] = tools
    _AlipayAppPayTools["new"] = AlipayAppPayTools()

@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,
    }

    if not _AlipayAppPayTools:
        _init_AlipayAppPayTools()

    order_info = _AlipayAppPayTools["old"].build_order_info_str_v1(
        out_trade_no=biz_content["out_trade_no"],
        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


