package com.yonge.toolset.payment.original.ali;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.result.BaseResult;
import com.yonge.toolset.base.util.StringUtil;
import com.yonge.toolset.payment.base.PaymentTemplate;
import com.yonge.toolset.payment.base.constant.PaymentConstant;
import com.yonge.toolset.payment.base.enums.*;
import com.yonge.toolset.payment.base.model.*;
import com.yonge.toolset.payment.base.model.callback.ClosePaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.ExecutePaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.PaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.RefundPaymentCallBack;
import com.yonge.toolset.payment.core.props.PaymentProperties;
import com.yonge.toolset.payment.core.service.SysConfigPaymentService;
import com.yonge.toolset.payment.core.util.RequestKitBean;
import com.yonge.toolset.payment.original.ali.constant.AlipayConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

@Component
public class OriginalAliAppTemplate implements PaymentTemplate {

    private final static Logger log = LoggerFactory.getLogger(OriginalAliAppTemplate.class);

    @Autowired
    private PaymentProperties paymentProperties;

    @Resource(name = "studentAlipayClient")
    private AlipayClient studentAlipayClient;

    @Resource(name = "teacherAlipayClient")
    private AlipayClient teacherAlipayClient;

    @Autowired
    private SysConfigPaymentService configPaymentService;

    @Autowired
    private RequestKitBean requestKitBean;

    @Override
    public BaseResult<Map<String, Object>> getOpenAuthMsg(OpenAuth openAuth) {
        return null;
    }

    @Override
    public BaseResult<Payment> executePayment(Payment payment) {
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        request.setNotifyUrl(paymentProperties.getNotifyUrl()
                + "/" + payment.getOpenType().getCode()
                + "/" + payment.getPaymentClient().getCode()
                + "/" + payment.getPayChannel().getCode()
                + "/executePayment");

        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payment.getPaymentNo());
        bizContent.put("total_amount", payment.getPayAmt());
        bizContent.put("subject", payment.getOrderTitle());

        List<Map<String, Object>> orderDetils = new ArrayList<>();
        for (OrderDetil orderDetil : payment.getOrderDetils()) {
            Map<String, Object> map = new HashMap<>();
            map.put("goods_id", orderDetil.getGoodsId());
            map.put("goods_name", orderDetil.getGoodName());
            map.put("quantity", orderDetil.getQuantity());
            map.put("price", orderDetil.getPrice());
            orderDetils.add(map);
        }
        bizContent.put("goods_detail", orderDetils);
        bizContent.put("merchant_order_no", payment.getOrderNo());
        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeAppPayResponse response = getAlipayClient(payment.getPaymentClient()).sdkExecute(request);
            log.info("支付宝-支付返回：{}", JSONObject.toJSONString(response));

            if (response.isSuccess()) {
                payment.setId(response.getTradeNo());
                payment.setPayInfo(response.getBody());
                return BaseResult.succeed(payment);
            } else {
                return BaseResult.failed(response.getMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return BaseResult.failed("交易失败");
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.failed("交易失败");
        }
    }

    @Override
    public BaseResult<Payment> queryPayment(Payment payment) {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

        JSONObject bizContent = new JSONObject();
        if (!StringUtil.isEmpty(payment.getId())) {
            bizContent.put("trade_no", payment.getId());
        }
        bizContent.put("out_trade_no", payment.getPaymentNo());

        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeQueryResponse response = getAlipayClient(payment.getPaymentClient()).execute(request);
            log.info("支付宝-查询返回：{}", JSONObject.toJSONString(response));

            if (response.isSuccess()) {
                payment.setPayAmt(response.getPayAmount());
                //获取交易状态
                String tradeStatus = response.getTradeStatus();
                if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
                    payment.setStatus(TradeStatusEnum.pending);
                } else if ("TRADE_CLOSED".equals(tradeStatus)) {
                    payment.setStatus(TradeStatusEnum.succeeded);
                } else if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    payment.setStatus(TradeStatusEnum.succeeded);
                } else if ("TRADE_FINISHED".equals(tradeStatus)) {
                    payment.setStatus(TradeStatusEnum.succeeded);
                }
                return BaseResult.succeed(payment);
            } else {
                return BaseResult.failed(response.getMsg() + ":" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return BaseResult.failed("查询失败");
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.failed("查询失败");
        }
    }

    @Override
    public BaseResult<ClosePayment> closePayment(ClosePayment closePayment) {
        if (StringUtil.isEmpty(closePayment.getPaymentNo())) {
            return BaseResult.failed("缺失渠道关单必要参数");
        }

        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();

        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", closePayment.getPaymentNo());

        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeCloseResponse response = getAlipayClient(closePayment.getPaymentClient()).execute(request);
            log.info("关单返回：{}", JSONObject.toJSONString(response));

            closePayment.setStatus(TradeStatusEnum.succeeded);
            //交易不存在
            if("ACQ.TRADE_NOT_EXIST".equals(response.getSubCode())){
                closePayment.setHasNotify(false);
                return BaseResult.succeed(closePayment);
            }
            if (response.isSuccess()) {
                return BaseResult.succeed(closePayment);
            } else {
                return BaseResult.failed(response.getMsg() + ":" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return BaseResult.failed("关单失败");
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.failed("关单失败");
        }
    }

    @Override
    public BaseResult<RefundBill> refundPayment(RefundBill refundBill) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

        JSONObject bizContent = new JSONObject();
        bizContent.put("trade_no", refundBill.getId());
        bizContent.put("out_trade_no", refundBill.getPaymentNo());
        bizContent.put("refund_amount", refundBill.getRefundAmt());
        bizContent.put("refund_reason", refundBill.getReason());
        bizContent.put("out_request_no", refundBill.getRefundNo());

        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeRefundResponse response = getAlipayClient(refundBill.getPaymentClient()).execute(request);
            log.info("退款返回：{}", JSONObject.toJSONString(response));

            if (response.isSuccess()) {
                //获取交易状态
                refundBill.setStatus(TradeStatusEnum.succeeded);
                return BaseResult.succeed(refundBill);
            } else {
                return BaseResult.failed(response.getMsg() + ":" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return BaseResult.failed("退款失败");
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.failed("退款失败");
        }
    }

    @Override
    public BaseResult<PaymentCallBack> analysisNotice(OpenEnum openType, PaymentClientEnum paymentClient, PayChannelEnum payChannel, MethodNameEnum methodName, HttpServletRequest request) {
        PaymentCallBack paymentCallBack = new PaymentCallBack();
        try {
            JSONObject jsonParams = requestKitBean.getReqParamJSON();
            log.info("支付宝回调,data is {}", jsonParams.toJSONString());

            //获取验签方式 是否使用证书 YES NO
            String USE_CERT = configPaymentService.getPaymentConfig(
                    OpenEnum.ORIGINAL, paymentClient, AlipayConstant.ALI_USE_CERT).getParamValue();
            String ALI_SIGN_TYPE = configPaymentService.getPaymentConfig(
                    OpenEnum.ORIGINAL, paymentClient, AlipayConstant.ALI_SIGN_TYPE).getParamValue();
            String ALI_ALIPAY_PUBLIC_KEY = configPaymentService.getPaymentConfig(
                    OpenEnum.ORIGINAL, paymentClient, AlipayConstant.ALI_ALIPAY_PUBLIC_KEY).getParamValue();
            String CERT_PATH = configPaymentService.getPaymentConfig(
                    OpenEnum.ORIGINAL, paymentClient, AlipayConstant.ALI_CERT_PATH).getParamValue();

            boolean verifyResult;
            if ("YES".equals(USE_CERT)) {
                verifyResult = AlipaySignature.rsaCertCheckV1(jsonParams.toJavaObject(Map.class), CERT_PATH,
                        PaymentConstant.CHARSET, ALI_SIGN_TYPE);
            } else {
                verifyResult = AlipaySignature.rsaCheckV1(jsonParams.toJavaObject(Map.class), ALI_ALIPAY_PUBLIC_KEY, PaymentConstant.CHARSET, ALI_SIGN_TYPE);
            }
            //验签失败
            if (!verifyResult) {
                return BaseResult.failed(HttpStatus.INTERNAL_SERVER_ERROR, paymentCallBack, "验签失败");
            }

            paymentCallBack.setId(jsonParams.getString("trade_no"));
            paymentCallBack.setPaymentNo(jsonParams.getString("out_trade_no"));

            //获取订单所处交易状态
            String trade_status = jsonParams.getString("trade_status");
            //退款单号
            String refundNo = jsonParams.getString("out_biz_no");

            paymentCallBack.setStatus(TradeStatusEnum.succeeded);
            paymentCallBack.setResMsg("success");
            //退款
            if (!StringUtil.isEmpty(refundNo)
                    || null != jsonParams.getBigDecimal("refund_fee")) {
                paymentCallBack.setMethodName(MethodNameEnum.refundPayment);
                //退款成功
                RefundPaymentCallBack refundPayment = new RefundPaymentCallBack();
                refundPayment.setBillNo(refundNo);
                refundPayment.setTransNo(jsonParams.getString("trade_no"));

                refundPayment.setRefundAmt(jsonParams.getString("refund_fee"));
                refundPayment.setTradeTime(jsonParams.getDate("gmt_refund"));
                paymentCallBack.setRefundPaymentCallBack(refundPayment);
            } else {
                if ("TRADE_CLOSED".equals(trade_status)) {
                    //关单成功
                    paymentCallBack.setMethodName(MethodNameEnum.closePayment);

                    ClosePaymentCallBack closePayment = new ClosePaymentCallBack();
                    closePayment.setTradeTime(jsonParams.getDate("gmt_close"));
                    paymentCallBack.setClosePaymentCallBack(closePayment);
                } else {
                    //支付成功
                    paymentCallBack.setMethodName(MethodNameEnum.executePayment);

                    ExecutePaymentCallBack executePayment = new ExecutePaymentCallBack();
                    String total_amount = jsonParams.getString("total_amount");

                    executePayment.setPayAmt(total_amount);
                    if (!StringUtil.isEmpty(total_amount)) {
                        String ALI_FEE_RATE = configPaymentService.getPaymentConfig(OpenEnum.ORIGINAL, AlipayConstant.ALI_FEE_RATE).getParamValue();
                        BigDecimal feeRate = new BigDecimal(StringUtil.isEmpty(ALI_FEE_RATE) ? "0.006" : ALI_FEE_RATE);
                        //支付宝不返回手续费，通过费率自己计算
                        executePayment.setFeeAmt(new BigDecimal(total_amount).multiply(feeRate).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
                    }
                    executePayment.setTradeTime(jsonParams.getDate("gmt_payment"));
                    paymentCallBack.setExecutePaymentCallBack(executePayment);
                }
            }
            return BaseResult.succeed(paymentCallBack);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            paymentCallBack.setResMsg("filed");
            return BaseResult.failed(HttpStatus.INTERNAL_SERVER_ERROR, paymentCallBack, "微信回调对象转换失败");
        } catch (Exception e) {
            e.printStackTrace();
            paymentCallBack.setResMsg("filed");
            return BaseResult.failed(HttpStatus.INTERNAL_SERVER_ERROR, paymentCallBack, "解析异常");
        }
    }

    /**
     * v1-v2
     *
     * @param v1
     * @param v2
     * @return
     */
    private String sub(String v1, String v2) {
        try {
            String s = new BigDecimal(v1).subtract(new BigDecimal(v2)).toString();
            return s;
        } catch (Exception e) {
            return null;
        }
    }


    private AlipayClient getAlipayClient(PaymentClientEnum paymentClient) {
        if (PaymentClientEnum.STUDENT.equals(paymentClient)) {
            return this.studentAlipayClient;
        }
        if (PaymentClientEnum.TEACHER.equals(paymentClient)) {
            return this.teacherAlipayClient;
        }
        throw new BizException("未知的客户端类型");
    }

}
