package com.ai.da.service.impl;

import cn.hutool.core.convert.Convert;
import com.ai.da.common.config.PayPalClient;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.enums.*;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.paypalRequest.AuthenticationRequest;
import com.ai.da.common.utils.paypalRequest.WebhookVerifyRequest;
import com.ai.da.mapper.primary.entity.OrderInfo;
import com.ai.da.mapper.primary.entity.RefundInfo;
import com.ai.da.model.dto.ProductPurchaseDTO;
import com.ai.da.service.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.paypal.api.payments.Event;
import com.paypal.base.Constants;
import com.paypal.base.SDKUtil;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.SerializeException;
import com.paypal.http.serializer.Json;
import com.paypal.orders.*;
import com.paypal.payments.CapturesGetRequest;
import com.paypal.payments.CapturesRefundRequest;
import com.paypal.payments.RefundRequest;
import com.paypal.payments.RefundsGetRequest;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.*;

import static com.ai.da.common.constant.PayPalCheckoutConstant.*;

@Slf4j
@Service
//@RefreshScope
public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {

    @Value("${paypal.receiver.email}")
    private String receiverEmail;

    @Value("${paypal.client-id}")
    private String clientId;

    @Value("${paypal.client-secret}")
    private String clientSecret;

    @Value("${paypal.mode}")
    private String mode;

    @Value("${paypal.webhook_id}")
    private String webhookId;

    @Resource
    private PayPalClient payPalClient;
    @Resource
    private OrderInfoService orderInfoService;
    @Resource
    private PaymentInfoService paymentInfoService;
    @Resource
    private RefundInfoService refundsInfoService;
    @Resource
    private CreditsService creditsService;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 创建订单的方法
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public HashMap<String, String> createOrder(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) throws SerializeException {
        // 生成订单
        log.info("生成订单");
        OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.PAYPAL.getType(), request);

        OrdersCreateRequest paypalRequest = new OrdersCreateRequest();
        paypalRequest.header("prefer", "return=representation");
        paypalRequest.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), productPurchaseDTO.getReturnUrl()));
        HttpResponse<Order> response = null;
        try {
            response = payPalClient.client(mode, clientId, clientSecret).execute(paypalRequest);
        } catch (Exception e) {
            log.error("调用paypal订单创建失败，失败原因 ===> {}", e.getMessage());
            throw new BusinessException("order.creation.failed");
        }

        String approve = "";
        assert response != null;
        if (response.statusCode() == 201) {
            log.info("Status Code = {}, Status = {}, OrderID = {}, Intent = {}", response.statusCode(), response.result().status(), response.result().id(), response.result().checkoutPaymentIntent());
            for (LinkDescription link : response.result().links()) {
                log.info("Links-{}: {}    \tCall Type: {}", link.rel(), link.href(), link.method());
                if (link.rel().equals("approve")) {
                    approve = link.href();
                }
            }
            String totalAmount = response.result().purchaseUnits().get(0).amountWithBreakdown().currencyCode() + ":" + response.result().purchaseUnits().get(0).amountWithBreakdown().value();
            log.info("Total Amount: {}", totalAmount);
            String json = new JSONObject(new Json().serialize(response.result())).toString(4);
            log.info("createOrder response body: {}", json);
        }

        String orderId = response.result().id();
        orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);

        HashMap<String, String> returnData = new HashMap<>();
        returnData.put("approve", approve);
        returnData.put("orderNo", orderId);

        // 需要返回地址和订单id
        return returnData;
    }

    // ##Validate Webhook
    public Boolean doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        try {
            String body = getBody(req);
            Map webhookEvent = new ObjectMapper().readValue(body, Map.class);

            HashMap<String, Object> webhookRequest = new HashMap<>();
            webhookRequest.put("auth_algo", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-AUTH-ALGO"));
            webhookRequest.put("cert_url", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-CERT-URL"));
            webhookRequest.put("transmission_id", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-ID"));
            webhookRequest.put("transmission_sig", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-SIG"));
            webhookRequest.put("transmission_time", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-TIME"));
            webhookRequest.put("webhook_id", webhookId);
            webhookRequest.put("webhook_event", webhookEvent);

            WebhookVerifyRequest webhookVerifyRequest = new WebhookVerifyRequest();
            webhookVerifyRequest.authorization(getOAuth());
            webhookVerifyRequest.requestBody(webhookRequest);
            // 验签
            HttpResponse<HashMap> verified = payPalClient.client(mode, clientId, clientSecret).execute(webhookVerifyRequest);
            boolean verifyResult = verified.result().get("verification_status").toString().equals("SUCCESS");
            if (verifyResult) {
                // ### Api Context
                APIContext apiContext = new APIContext(clientId, clientSecret, mode);

                // Set the webhookId that you received when you created this webhook.
                apiContext.addConfiguration(Constants.PAYPAL_WEBHOOK_ID, webhookId);
                Boolean result = Event.validateReceivedEvent(apiContext, getHeadersInfo(
                        req), body);
                log.info("Webhook Validated:  " + result);

                if (result) {
                    // 处理订单数据
                    LinkedHashMap<String, LinkedHashMap<String, String>> webhookEventMap = (LinkedHashMap<String, LinkedHashMap<String, String>>) webhookEvent;
                    String orderId = webhookEventMap.get("resource").get("id");
                    processOrder(orderId);
                    return Boolean.TRUE;
                }
            } else {
                log.error("Paypal 验签失败");
            }
        } catch (PayPalRESTException | InvalidKeyException | NoSuchAlgorithmException | SignatureException e) {
            log.error(e.getMessage());
        }
        return Boolean.FALSE;
    }

    // Simple helper method to help you extract the headers from HttpServletRequest object.
    private static Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> map = new HashMap<String, String>();
        @SuppressWarnings("rawtypes")
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }

    // Simple helper method to fetch request data as a string from HttpServletRequest object.
    public String getBody(HttpServletRequest request) throws IOException {
        String body;
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        body = stringBuilder.toString();
        log.info("回调参数 ===> {}", body);
        return body;
    }

    /**
     * 生成订单主体信息
     */
    private OrderRequest buildRequestBody(String price, String returnUrl) {
        OrderRequest orderRequest = new OrderRequest();
        orderRequest.checkoutPaymentIntent(CAPTURE);

        ApplicationContext applicationContext = new ApplicationContext()
                .brandName(BRANDNAME)
                .landingPage(LANDINGPAGE)
                .cancelUrl(returnUrl).returnUrl(returnUrl)
                .userAction(USERACTION)
                .shippingPreference(SHIPPINGPREFERENCE);
        orderRequest.applicationContext(applicationContext);

        List<PurchaseUnitRequest> purchaseUnitRequests = new ArrayList<PurchaseUnitRequest>();

        PurchaseUnitRequest purchaseUnitRequest = new PurchaseUnitRequest()
                .amountWithBreakdown(new AmountWithBreakdown()
                        .amountBreakdown(new AmountBreakdown())
                        .currencyCode(CurrencyCodesEnum.HONG_KONG_DOLLAR.getCode())
                        .value(price));
        purchaseUnitRequests.add(purchaseUnitRequest);
        orderRequest.purchaseUnits(purchaseUnitRequests);
        return orderRequest;
    }

    /*@Override
    public String callback(@SuppressWarnings("rawtypes") Map map) {

        log.info("paypal支付通知正在执行");
        log.info("通知参数 ===> {}", map);

//        log.info(map.toString());
        String outTradeNo = (String) map.get("invoice");
        String paymentStatus = (String) map.get("payment_status");
        String amount = (String) map.get("mc_gross");
        String currency = (String) map.get("mc_currency");
        String paymentId = (String) map.get("txn_id");
        String parentPaymentId = (String) map.get("parent_txn_id");
        log.info("商家订单号 = {}", outTradeNo);
        log.info("订单状态 = {}", paymentStatus);
        log.info("金额 = {}", amount);
        log.info("币种 = {}", currency);
        log.info("流水号 = {}", paymentId);
        log.info("父流水号 = {}", parentPaymentId);

        if (!receiverEmail.equals(map.get("receiver_email"))) {
            log.info("FAIL = 商户id错误, outTradeNo = {}", outTradeNo);
            return "failure";
        }
        if ("Completed".equals(paymentStatus)) {
            //进行数据库操作
            //
            //
            log.info("支付成功,状态为=COMPLETED");
            return "success";
        }
        if ("Refunded".equals(paymentStatus)) {
            //进行数据库操作
            //
            //
            log.info("退款成功");
            return "success";
        }
        if ("Pending".equals(paymentStatus) && StringUtils.isEmpty(parentPaymentId)) {
            String pendingReason = String.valueOf(map.get("pending_reason"));
            //进行数据库操作
            //
            //
            log.info("订单支付成功,状态为=PENDING，产生此状态的原因是 {}", pendingReason);
            return "success";
        }
        if (StringUtils.isEmpty(parentPaymentId)) {
            if (PayPalCheckoutConstant.PAYMENT_STATUS_REVERSED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_CANCELED_REVERSAL.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_DENIED.equals(paymentStatus)) {
                String reasonCode = String.valueOf(map.get("reason_code"));
                //进行数据库操作(状态修改)
                //
                //
                log.info("订单异常,请尽快查看处理，状态为={}，产生此状态的原因是 {} ", paymentStatus, reasonCode);
                return PayPalCheckoutConstant.SUCCESS;
            }
            if (PayPalCheckoutConstant.PAYMENT_STATUS_EXPIRED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_CREATED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_FAILED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_PROCESSED.equals(paymentStatus)
                    || PayPalCheckoutConstant.PAYMENT_STATUS_VOIDED.equals(paymentStatus)) {
                //进行数据库操作(状态修改)
                //
                //
                log.info("其他订单状态,订单异常,请尽快查看处理， 状态={}", paymentStatus);
                return PayPalCheckoutConstant.SUCCESS;
            }
        }
        return "failure";
    }*/

    /**
     * 查询订单信息
     *
     * @param orderNo
     * @return
     * @throws SerializeException
     */
    public Order queryOrder(String orderNo) throws SerializeException {
        OrdersGetRequest request = new OrdersGetRequest(orderNo);

        HttpResponse<Order> response = null;
        try {
            response = payPalClient.client(mode, clientId, clientSecret).execute(request);
        } catch (Exception e) {
            log.error("paypal订单查询失败，失败原因 ===> {}", e.getMessage());
            return null;
        }
        log.debug("Status Code: " + response.statusCode() + "\tStatus: " + response.result().status() + "\tOrder id: " + response.result().id());
        if (response.result().purchaseUnits().get(0).payments() != null) {
            List<Capture> captures = response.result().purchaseUnits().get(0).payments().captures();
            if (captures != null) {
                for (Capture capture : captures) {
                    log.debug("\t订单编号= " + capture.invoiceId() + "\tCapture Id= " + capture.id() + "\tCapture status= " + capture.status() + "\tCapture amount= " + capture.amount().currencyCode() + ":" + capture.amount().value());
                }
            }
            List<Refund> refunds = response.result().purchaseUnits().get(0).payments().refunds();
            if (refunds != null) {
                for (Refund refund : refunds) {
                    log.debug("\t售后编号= " + refund.invoiceId() + "\tRefund Id= " + refund.id() + "\tRefund status= " + refund.status() + "\tRefund amount= " + refund.amount().currencyCode() + ":" + refund.amount().value());
                }
            }
        }
        for (com.paypal.orders.LinkDescription link : response.result().links()) {
            log.debug("Links: \t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
        }


        String json = new JSONObject(new Json().serialize(response.result())).toString(4);
        log.info("Full response body: {}", json);
        return response.result();
    }

    /**
     * 用户授权支付成功，进行扣款操作
     */
    @Transactional(rollbackFor = Exception.class)
    public Order captureOrder(String orderId) {
        OrdersCaptureRequest request = new OrdersCaptureRequest(orderId);
        request.requestBody(new OrderRequest());
        PayPalClient payPalClient = new PayPalClient();
        HttpResponse<Order> response;

        try {
            response = payPalClient.client(mode, clientId, clientSecret).execute(request);
        } catch (Exception e) {
            log.error("调用paypal扣款失败，失败原因 ===> {}", e.getMessage());
            throw new BusinessException("order.deduction.failed");
        }
        log.info("Status Code = {}, Status = {}, OrderID = {}", response.statusCode(), response.result().status(), response.result().id());
        for (LinkDescription link : response.result().links()) {
            log.info("Links-{}: {}    \tCall Type: {}", link.rel(), link.href(), link.method());
        }
        for (PurchaseUnit purchaseUnit : response.result().purchaseUnits()) {
            for (Capture capture : purchaseUnit.payments().captures()) {
                log.info("Capture id: {}", capture.id());
                log.info("status: {}", capture.status());
                log.info("invoice_id: {}", capture.invoiceId());
                if ("COMPLETED".equals(capture.status())) {
                    //进行数据库操作，修改订单状态为已支付成功，尽快发货（配合回调和CapturesGet查询确定成功）
                    log.info("支付成功,状态为=COMPLETED");
                }
                if ("PENDING".equals(capture.status())) {
                    log.info("status_details: {}", capture.captureStatusDetails().reason());
                    String reason = "PENDING";
                    if (capture.captureStatusDetails() != null && capture.captureStatusDetails().reason() != null) {
                        reason = capture.captureStatusDetails().reason();
                    }
                    //进行数据库操作，修改订单状态为已支付成功，但触发了人工审核，请审核通过后再发货（配合回调和CapturesGet查询确定成功）
                    log.info("支付成功,状态为=PENDING : {}", reason);
                }
            }
        }
        Payer buyer = response.result().payer();
        log.info("Buyer Email Address: {}", buyer.email());
        log.info("Buyer Name: {} {}", buyer.name().givenName(), buyer.name().surname());
//        String jsonString = JSON.toJSONString(response.result());
        String json = null;
        try {
            json = new JSONObject(new Json().serialize(response.result())).toString(4);
        } catch (SerializeException e) {
            log.warn("response序列化出错，具体信息 ===> {}", e.getMessage());
        }
        log.info("captureOrder response body: {}", json);
//        return Convert.toStr(new Json().serialize(response.result()));
        return response.result();
    }

    /**
     * 查询扣款
     */
    public String queryCapture(String orderNo) throws IOException {
        CapturesGetRequest request = new CapturesGetRequest("扣款id， CaptureOrder生成");

        HttpResponse<com.paypal.payments.Capture> response = payPalClient.client(mode, clientId, clientSecret).execute(request);
        System.out.println("Status Code: " + response.statusCode());
        System.out.println("Status: " + response.result().status());
        System.out.println("Capture ids: " + response.result().id());
        System.out.println("Links: ");
        for (com.paypal.payments.LinkDescription link : response.result().links()) {
            System.out.println("\t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
        }
        System.out.println("Full response body:");
        System.out.println(new JSONObject(new Json().serialize(response.result())).toString(4));
        return null;
    }


    /**
     * 申请退款
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean refundOrder(String orderNo, String reason) throws IOException {

        RefundInfo refundByOrderNo = refundsInfoService.createRefundByOrderNo(orderNo, reason);

        OrdersGetRequest ordersGetRequest = new OrdersGetRequest(orderNo);
        PayPalClient payPalClient = new PayPalClient();
        HttpResponse<com.paypal.orders.Order> ordersGetResponse = null;
        ordersGetRequest.authorization("Bearer " + getOAuth());
        boolean result;
        try {
            ordersGetResponse = payPalClient.client(mode, clientId, clientSecret).execute(ordersGetRequest);
        } catch (Exception e) {
            log.error("调用paypal订单查询失败，失败原因 ===> {}", e.getMessage());
            throw new BusinessException("order.query.failed");
        }
        String captureId = ordersGetResponse.result().purchaseUnits().get(0).payments().captures().get(0).id();
        CapturesRefundRequest request = new CapturesRefundRequest(captureId);
        request.authorization("Bearer " + getOAuth());
        request.prefer("return=representation");

        OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
        request.requestBody(buildRefundRequestBody(String.valueOf(orderInfo.getTotalFee()), reason));
        HttpResponse<com.paypal.payments.Refund> response = null;
        try {
            response = payPalClient.client(mode, clientId, clientSecret).execute(request);
        } catch (IOException e) {
            log.error("调用paypal退款申请失败，失败原因 {}", e.getMessage());
            throw new BusinessException("Request for refund failed");
        }

        log.info("Status Code = {}, Status = {}, RefundID = {}", response.statusCode(), response.result().status(), response.result().id());
        if ("COMPLETED".equals(response.result().status())) {
            //进行数据库操作，修改状态为已退款（配合回调和退款查询确定退款成功）

            //更新订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.REFUND_SUCCESS);

            refundsInfoService.updateRefundForPayPal(
                    refundByOrderNo.getId(),
                    response.result().id(),
                    new Gson().toJson(response.result(), com.paypal.payments.Refund.class),
                    AliPayTradeStateEnum.REFUND_SUCCESS.getType()); //退款成功

            // 更新积分状态
            OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo);
//            creditsService.creditsRefund(orderByOrderNo.getAccountId(), orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue()));
            creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())), orderNo);
            log.info("退款成功");
            result = Boolean.TRUE;
        } else {
            //更新订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.REFUND_ABNORMAL);

            //更新退款单
            refundsInfoService.updateRefundForPayPal(
                    refundByOrderNo.getId(),
                    response.result().id(),
                    new Gson().toJson(response.result(), com.paypal.payments.Refund.class),
                    AliPayTradeStateEnum.REFUND_ERROR.getType()); //退款失败
            result = Boolean.FALSE;
        }
        for (com.paypal.payments.LinkDescription link : response.result().links()) {
            log.info("Links-{}: {}    \tCall Type: {}", link.rel(), link.href(), link.method());
        }
        String json = new JSONObject(new Json().serialize(response.result())).toString(4);
        log.info("refundOrder response body: {}", json);
        return result;
    }

    public RefundRequest buildRefundRequestBody(String price, String reason) {
        RefundRequest refundRequest = new RefundRequest();
        com.paypal.payments.Money money = new com.paypal.payments.Money();
        money.currencyCode(CurrencyCodesEnum.HONG_KONG_DOLLAR.getCode());
        money.value(price);
        refundRequest.amount(money);
//        refundRequest.invoiceId("P2020052514440001");
        refundRequest.noteToPayer(reason);
        try {
            log.info("refund order body : {}", Convert.toStr(new Json().serialize(refundRequest)));
        } catch (SerializeException e) {
            throw new RuntimeException(e);
        }

        return refundRequest;
    }

    /**
     * 查询退款
     */
    public String queryRefund(String orderNo) throws IOException {
        RefundsGetRequest request = new RefundsGetRequest("退款id RefundOrder生成");
        HttpResponse<com.paypal.payments.Refund> response = payPalClient.client(mode, clientId, clientSecret).execute(request);
        System.out.println("Status Code: " + response.statusCode());
        System.out.println("Status: " + response.result().status());
        System.out.println("Refund Id: " + response.result().id());
        System.out.println("Links: ");
        for (com.paypal.payments.LinkDescription link : response.result().links()) {
            System.out.println("\t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
        }
        System.out.println("Full response body:");
        System.out.println(new JSONObject(new Json().serialize(response.result())).toString(4));
        return null;
    }

    public String getOAuth() {
        // 1、判断缓存区是否有该token
        Boolean hasKey = redisUtil.hasKey(PAYPAL_TOKEN_KEY);
        if (hasKey) {
            return redisUtil.getFromString(PAYPAL_TOKEN_KEY);
//            return "A21AAKnpozur9r9omqQ2ge5aXHBBdEERi5F8FIgNYOjhhO2N7rjmkz2irh2lScpBO3s3Cqukw3eZkpYZ4YWE7rIacjv7MHmow";
        }

        // 2、无或者过期，重新获取token，返回
        AuthenticationRequest authenticationRequest = new AuthenticationRequest();
        authenticationRequest.authorization(clientId, clientSecret);
        try {
            HttpResponse<HashMap> authResult = payPalClient.client(mode, clientId, clientSecret).execute(authenticationRequest);
            String accessToken = authResult.result().get("access_token").toString();
            long expiresIn = Long.parseLong(authResult.result().get("expires_in").toString());
            // 3、存redis
            redisUtil.addToString(PAYPAL_TOKEN_KEY, accessToken, expiresIn);
            return accessToken;
        } catch (IOException e) {
            log.error("获取paypal token失败，失败原因 ===> {}", e.getMessage());
            throw new BusinessException(e);
        }
    }

    // 处理当前订单
    @Transactional(rollbackFor = Exception.class)
    public void processOrder(String orderNo) {
        // 1、确定当前订单是否已经被扣款
        OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);
        if (orderInfo.getOrderStatus().equals(OrderStatusEnum.SUCCESS.getType())) {
            // 直接返回
            return;
        }
        // 发起扣款请求
        Order capturedOrder = captureOrder(orderNo);
        // 业务处理
        if (PayPalOrderStatusEnum.COMPLETED.getStatus().equals(capturedOrder.status())) {
            //更新订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS);
            //记录支付日志
            paymentInfoService.createPaymentInfoForPayPal(capturedOrder, "credits");
            float quantity = orderInfo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue());
            // 更新积分
            creditsService.buyCredits(orderInfo.getAccountId(), quantity);
            // 添加积分变更记录
            creditsService.insertToCreditsDetail(orderInfo.getAccountId(),
                    CreditsEventsEnum.BUY_CREDITS.getName() + "--PayPal",
                    String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)),
                    "positive", orderNo);
        }
    }

    @Override
    public void checkOrderStatus(String orderNo) throws SerializeException {

        log.warn("根据订单号核实订单状态 ===> {}", orderNo);

        Order result = this.queryOrder(orderNo);

        // 订单未创建 | 订单异常 | 订单创建过但未支付
        if(result == null || PayPalOrderStatusEnum.CREATED.getStatus().equals(result.status())){
            log.warn("核实订单未创建 ===> {}", orderNo);
            //更新本地订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.TIMEOUT_CLOSED);
            return ;
        }

        // 解析查单响应结果
        String tradeStatus = result.status();
        OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo);

        // 支付了，但还没完成
        if(PayPalOrderStatusEnum.APPROVED.getStatus().equals(tradeStatus)){
            log.warn("核实订单未支付 ===> {}", orderNo);
            // 更新商户端订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.ORDER_PROCESSING);
        }

        if(PayPalOrderStatusEnum.COMPLETED.getStatus().equals(tradeStatus)){
            log.warn("核实订单已支付 ===> {}", orderNo);
            //如果订单已支付，则更新商户端订单状态
            orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS);
            //并记录支付日志
            paymentInfoService.createPaymentInfoForPayPal(result, "credits");
            float quantity = orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue());
            // 更新积分
//            creditsService.buyCredits(orderByOrderNo.getAccountId(),orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue()));
            creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity);
            // 添加积分变更记录
            creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(),
                    CreditsEventsEnum.BUY_CREDITS.getName() + "--Paypal",
                    String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)),
                    "positive", orderNo);
        }

    }
}


