package com.bohuikeji.delivery.backstage.pay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.*;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.bohuikeji.delivery.backstage.entity.AliPayConfig;
import com.bohuikeji.frame.module.admin.component.StaticComponent;
import com.bohuikeji.frame.module.admin.entity.vo.AlipayVo;
import com.bohuikeji.frame.module.admin.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付宝支付请求类
 */
@Slf4j
public class AliPay {
    /**
     * 静态内部类
     * App公钥证书加签方式
     */
    private static class AlipayClientHolder {
        private static AlipayClient alipayClient;
        static {
            //构造client
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
            //设置网关地址
            certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
            //设置应用Id
            certAlipayRequest.setAppId(AliPayConfig.appID);
            //设置应用私钥
            certAlipayRequest.setPrivateKey(AliPayConfig.privateKey);
            //设置请求格式，固定值json
            certAlipayRequest.setFormat("json");
            //设置字符集
            certAlipayRequest.setCharset(AliPayConfig.charset);
            //设置签名类型
            certAlipayRequest.setSignType(AliPayConfig.signType);
            //设置应用公钥证书路径
            certAlipayRequest.setCertPath(AliPayConfig.appCertPath);
            //设置支付宝公钥证书路径
            certAlipayRequest.setAlipayPublicCertPath(AliPayConfig.alipayCertPath);
            //设置支付宝根证书路径
            certAlipayRequest.setRootCertPath(AliPayConfig.alipayRootCertPath);
            //构造client
            try {
                alipayClient = new DefaultAlipayClient(certAlipayRequest);
            } catch (AlipayApiException e) {
                log.error("支付宝客户端初始化错误:",e);
                e.printStackTrace();
            }
        }
    }

    /**
     * 支付宝小程序公钥证书加签方式
     */
    public static class aliClient {
        public static AlipayClient alipayBycodeClient;
        static {
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest ();
            certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
            certAlipayRequest.setAppId(AliPayConfig.AliClientID);
            certAlipayRequest.setPrivateKey(AliPayConfig.APP_PRIVATE_KEY);
            certAlipayRequest.setFormat("json");
            certAlipayRequest.setCharset("GBK");
            certAlipayRequest.setSignType("RSA2");
            certAlipayRequest.setCertPath(AliPayConfig.appclientCertPath);
            certAlipayRequest.setAlipayPublicCertPath(AliPayConfig.alipayclientCertPath);
            certAlipayRequest.setRootCertPath(AliPayConfig.alipayclientRootCertPath);
            try {
                alipayBycodeClient = new DefaultAlipayClient(certAlipayRequest);
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 获取客户端
     * @return
     */
    public static AlipayClient getClient(){
        return AlipayClientHolder.alipayClient;
    }

    /**
     * 支付宝条码支付
     * （客户出示付款码，商家扫码后支付成功）
     * @param authCode 支付码
     * @param outTradeNo 订单号
     * @param totalAmount 订单标题
     * @param subject 订单金额
     * @return
     */
    public static AlipayTradePayResponse alipaycode(String authCode, String outTradeNo, String totalAmount, String subject) {
        //创建API对应的request类
        AlipayTradePayRequest request = new AlipayTradePayRequest();
        request.setNotifyUrl(StaticComponent.ALIPAY_NOTIFY_URL);
        Map<String,Object> maps = new HashMap<>();
        maps.put("auth_code",authCode);
        maps.put("out_trade_no",outTradeNo);
        maps.put("scene","bar_code");
        maps.put("total_amount",totalAmount);
        maps.put("subject",subject);
        maps.put("method","alipay.trade.app.pay");
        String req = JSONObject.toJSONString(maps);
        request.setBizContent(req);
        //通过alipayClient调用API，获得对应的response类
        AlipayTradePayResponse response = null;
        try {
            response = getClient().certificateExecute(request);
            log.info("付款回调:"+response.getBody());
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info(e.getErrMsg());
            return null;
        }
        return response;
    }

    /**
     * 当面付
     * 收银员通过收银台或商户后台调用支付宝接口，生成二维码后，展示给用户，由用户扫描二维码完成订单支付。
     * @param outTradeNo 客户支付订单号
     * @param totalAmount 订单金额
     * @param subject 订单说明
     * @return
     */
    public static String alipayPrecreate(String outTradeNo, String totalAmount, String subject) {
        //创建API对应的request类
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        request.setNotifyUrl(StaticComponent.ALIPAY_NOTIFY_URL);
        Map<String,Object> maps = new HashMap<>();
        maps.put("out_trade_no",outTradeNo);
        maps.put("scene","bar_code");
        maps.put("total_amount",totalAmount);
        maps.put("subject",subject);
        maps.put("method","alipay.trade.precreate");
        String req = JSONObject.toJSONString(maps);
        request.setBizContent(req);
        //通过alipayClient调用API，获得对应的response类
        AlipayTradePrecreateResponse response = null;
        try {
            response = getClient().certificateExecute(request);
            log.info("付款回调:"+response.getBody());
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info(e.getErrMsg());
            return null;
        }
        return response.getQrCode();
    }


    /**
     * 支付宝App支付
     * @param courierNum 商户订单号
     * @param orderFactPrice 支付金额
     * @return
     */
    public static String aliAppPay(String courierNum,String orderFactPrice) {
        //设置请求参数
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(courierNum);
        model.setTotalAmount(orderFactPrice);
        model.setSubject("同城急送");
        model.setTimeoutExpress("90m");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(StaticComponent.ALIPAY_NOTIFY_URL);
        String orderStr = "";
        AlipayTradeAppPayResponse response =null;
        try {
            response = getClient().sdkExecute(request);
            orderStr = response.getBody();
            log.info("派送员缴费支付 [{}]",orderStr);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return orderStr;
    }

    /**
     * 支付宝小程序支付
     * @param payNum
     * @param orderFactPrice
     * @param userId
     * @return
     */
    public static JSONObject alipayClient (String payNum,String orderFactPrice,String userId) {
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        request.setNotifyUrl(StaticComponent.ALIPAY_NOTIFY_URL);
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNum);
        bizContent.put("total_amount",orderFactPrice);
        bizContent.put("subject", "同城急送");
        bizContent.put("buyer_id", userId);
        bizContent.put("timeout_express", "90m");
        request.setBizContent(bizContent.toString());
        JSONObject orderStr = null;
        AlipayTradeCreateResponse response = null;
        try {
            response = aliClient.alipayBycodeClient.certificateExecute(request);
            orderStr = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_trade_create_response");
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return orderStr;
    }


    /**
     * 查询订单接口
     * @param outTradeNo 商户订单号
     * @param tradeNo 支付宝交易号
     * @param outTradeNo
     * @param tradeNo
     * @return
     */
    public static AlipayTradeQueryResponse aliQuery(String outTradeNo, String tradeNo) {
        //设置请求参数
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        AlipayTradeQueryResponse response = null;
        try {
            response = getClient().certificateExecute(request);
            System.out.println("订单查询返回结果为："+response.getBody());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 撤销订单接口
     * @param outTradeNo 商户订单号
     * @param tradeNo 支付宝交易号
     * @param outTradeNo
     * @param tradeNo
     * @return
     */
    public static AlipayTradeCancelResponse aliCancel(String outTradeNo, String tradeNo) {
        //设置请求参数
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        AlipayTradeCancelModel model = new AlipayTradeCancelModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        AlipayTradeCancelResponse response = null;
        try {
            response = getClient().certificateExecute(request);
            System.out.println("订单查询返回结果为："+response.getBody());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 支付宝统一退款接口
     * @param orderNum 商户订单号
     * @param trade_no 支付宝交易号
     * @param orderFactPrice 退款的金额
     * @param refundReason 退款的原因说明
     * @param out_request_no  标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传
     * @return
     */
    public static AlipayTradeRefundResponse refund(String orderNum, String orderFactPrice,String trade_no, String refundReason,String out_request_no) {
        //设置参数
        AlipayTradeRefundModel model=new AlipayTradeRefundModel();
        model.setOutTradeNo(orderNum);
        model.setTradeNo(trade_no);
        model.setRefundAmount(orderFactPrice);
        model.setRefundReason(refundReason);
        model.setOutRequestNo(out_request_no);
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
        alipayRequest.setBizModel(model);
        AlipayTradeRefundResponse alipayResponse = null;
        try {
            alipayResponse = getClient().certificateExecute(alipayRequest);
            log.info("支付宝退款API返回:"+alipayResponse.getBody());
        } catch (AlipayApiException e) {
            System.out.println("订单退款失败，异常原因:"+ e);
            log.error("订单退款失败，异常原因:{}", e);
            return null;
        }
        return alipayResponse;
    }

    /**
     * 支付宝小程序退款
     * @param orderNum
     * @param orderFactPrice
     * @param trade_no
     * @param refundReason
     * @param out_request_no
     * @return
     */
    public static JSONObject clientRefund(String orderNum, String orderFactPrice,String trade_no, String refundReason,String out_request_no) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderNum);
        bizContent.put("trade_no", trade_no);
        bizContent.put("refund_amount", orderFactPrice);
        bizContent.put("refund_reason", refundReason);
        bizContent.put("out_request_no", out_request_no);
        request.setBizContent(bizContent.toString());
        AlipayTradeRefundResponse response = null;
        try {
            response = aliClient.alipayBycodeClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if(response.isSuccess()){
            return JSONObject.parseObject(response.getBody()).getJSONObject("alipay_trade_refund_response");
        }
        return null;
    }


    /**
     * 获取支付宝App用户信息
     * @param code
     * @return
     */
    public static AlipayUserInfoShareResponse getUserInfo(String code){
        AlipaySystemOauthTokenRequest authRequest = new AlipaySystemOauthTokenRequest();
        authRequest.setCode(code);
        authRequest.setGrantType("authorization_code");
        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = getClient().certificateExecute(authRequest);
            System.out.println(oauthTokenResponse.getAccessToken());
            AlipayUserInfoShareRequest shareRequest = new AlipayUserInfoShareRequest();
            AlipayUserInfoShareResponse response = getClient().certificateExecute(shareRequest, oauthTokenResponse.getAccessToken());
            if (response.isSuccess()) {
                System.out.println("调用成功");
                System.out.println(ReflectionToStringBuilder.toString(response));
                String userId = response.getUserId();
            } else {
                System.out.println("调用失败");
                System.out.println(response.getSubCode() + ":" + response.getSubMsg());
            }
            return response;

        } catch (AlipayApiException e) {
            //处理异常
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 支付宝小程序获取UserId信息
     * @param code
     * @return
     * @throws AlipayApiException
     */
    public static JSONObject getUserId(String code) throws AlipayApiException {
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType("authorization_code");
        request.setCode(code);
        AlipaySystemOauthTokenResponse response = aliClient.alipayBycodeClient.certificateExecute(request);
        if(response.isSuccess()){
            String body = response.getBody();
            if(!StringUtils.isEmpty(body)){
                JSONObject jsonObject = JSONObject.parseObject(body);
                JSONObject object = jsonObject.getJSONObject(AliPayConfig.ALIPAY_SYSTEM_OAUTH_TOKEN_RESPONSE);
                return object;
            }
        } else {
        }
        return null;
    }

    /**
     * 执行查询
     * @param request
     * @return
     */
    public  static AlipayResponse execute(AlipayRequest request){
        try {
            return getClient().certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("【支付宝接口调用失败】单笔转账接口调用失败，请求错误！返回null：",e);
            return null;
        }
    }

    /**
     * 转账到支付宝账户
     * @param out_biz_no
     * @param trans_amount
     * @param identity
     * @return
     */
    public static AlipayFundTransUniTransferResponse transferToAlipay(String out_biz_no,String trans_amount,String title,String identity){
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        AlipayFundTransUniTransferModel model=new AlipayFundTransUniTransferModel();
        model.setOutBizNo(out_biz_no);
        model.setTransAmount(trans_amount);
        model.setProductCode("TRANS_ACCOUNT_NO_PWD");
        model.setBizScene("DIRECT_TRANSFER");
        model.setOrderTitle(title);
        Participant payeeInfo=new Participant();
        payeeInfo.setIdentity(identity);
        //payeeInfo.setName(name);
        payeeInfo.setIdentityType("ALIPAY_USER_ID");
        model.setPayeeInfo(payeeInfo);
        request.setBizModel(model);
        try {
            return getClient().certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("【支付宝接口调用失败】单笔转账接口调用失败，请求错误！返回null：",e);
            return null;
        }
    }

    /**
     * 查询账户余额
     * @return
     */
    public static AlipayFundAccountQueryResponse queryAccount() {
        AlipayFundAccountQueryRequest request = new AlipayFundAccountQueryRequest();
        AlipayFundAccountQueryModel model=new AlipayFundAccountQueryModel();
        model.setAlipayUserId(AliPayConfig.userId);
        model.setAccountType("ACCTRANS_ACCOUNT");
        request.setBizModel(model);
        AlipayFundAccountQueryResponse response = null;
        try {
            response = getClient().certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("【支付宝接口调用失败】账户余额查询接口调用失败，请求错误！返回null：",e);
            return null;
        }
        return response;
    }

    /**
     * 支付宝的验签方法
     * @param req
     * @return
     */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> params = new HashMap<>();
        requestMap.forEach((key, values) -> {
            String strs = "";
            for (String value : values) {
                strs = strs + value;
            }
            /*System.out.println(("key值为" + key + "value为：" + strs));*/
            params.put(key, strs);
        });

        //调用SDK验证签名
        try {
            return AlipaySignature.rsaCheckV1(params, AlipayVo.alipay_public_key, AlipayVo.charset, AlipayVo.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************验签失败********************");
            return false;
        }
    }


}
