package com.xhpc.payment.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.AntCertificationUtil;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeCreateRequest;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.xhpc.common.api.PowerPileService;
import com.xhpc.common.core.constant.HttpStatus;
import com.xhpc.common.core.constant.StatusConstants;
import com.xhpc.common.core.domain.R;
import com.xhpc.common.core.utils.StringUtils;
import com.xhpc.common.core.web.domain.AjaxResult;
import com.xhpc.common.data.down.StartChargingData;
import com.xhpc.payment.domain.AlipayNotifyParam;
import com.xhpc.payment.domain.XhpcAppUser;
import com.xhpc.payment.domain.XhpcRechargeOrder;
import com.xhpc.payment.domain.XhpcUserAccountStatement;
import com.xhpc.payment.mapper.XhpcUserAccountStatementMapper;
import com.xhpc.payment.service.IXhpcRechargeOrderService;
import com.xhpc.payment.service.IXhpcRefundOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;


@RestController
@RequestMapping("/alipay")
@Api(value = "支付宝支付接口", tags = "支付宝支付接口")
public class AlipayPaymentController {

    @Autowired
    private Environment environment;
    @Autowired
    private IXhpcRechargeOrderService iXhpcRechargeOrderService;
    @Autowired
    private XhpcUserAccountStatementMapper xhpcUserAccountStatementMapper;
    @Autowired
    private PowerPileService powerPileService;
    @Autowired
    private IXhpcRefundOrderService iXhpcRefundOrderService;

    private static final Logger logger = LoggerFactory.getLogger(AlipayPaymentController.class);

    @PostMapping("/payment")
    @ApiOperation(value = "支付宝支付")
    private AjaxResult payment(HttpServletRequest servletRequest, @RequestBody Map<String, Object> map) throws Exception {
        String openid = StringUtils.valueOf(map.get("openid"));
        if (StringUtils.isEmpty(openid)) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "openid不能为空");
        }
        //总金额(是)订单总金额，单位为元
        String amount = StringUtils.valueOf(map.get("amount"));
        if (StringUtils.isEmpty(amount)) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能为空");
        }else{
            if(new BigDecimal(5).compareTo(new BigDecimal(amount))==1){
                return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能少于5元");
            }
        }
        //用户信息id
        String userId = StringUtils.valueOf(map.get("userId"));
        if (StringUtils.isEmpty(userId)) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "用户信息不能为空");
        }
        Map<String, Object> refundOrder = iXhpcRefundOrderService.getNotRefundOrder(Long.parseLong(userId));
        if (StringUtils.isNotNull(refundOrder)) {
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "用户存正在退款");
        }
        String orderNumber = StringUtils.numFormat(Long.parseLong(userId), 1, StatusConstants.FLOWING_WATER_RECHARGE_TYPE);

        //生成充值订单
        XhpcRechargeOrder xhpcRechargeOrder = iXhpcRechargeOrderService.addRechargeOrder(userId, BigDecimal.valueOf(Double.parseDouble(amount)), "2", orderNumber);
        String attach = attachYu(StringUtils.valueOf(xhpcRechargeOrder.getRechargeOrderId()), StringUtils.valueOf(amount), null, orderNumber);

        /** 初始化 **/
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        /** 支付宝网关 **/
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        /** 应用id，如何获取请参考：https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
        certAlipayRequest.setAppId(environment.getProperty("ALIPAYAPPID"));
        /** 应用私钥, 如何获取请参考：https://opensupport.alipay.com/support/helpcenter/207/201602471154?ant_source=antsupport  **/
        certAlipayRequest.setPrivateKey(environment.getProperty("ALIPAYPRIVATEKEY"));
        /** 应用公钥证书路径，下载后保存位置的绝对路径  **/
        certAlipayRequest.setCertPath(environment.getProperty("CERTPATH"));
        /** 支付宝公钥证书路径，下载后保存位置的绝对路径 **/
        certAlipayRequest.setAlipayPublicCertPath(environment.getProperty("PUBLICCERTPATH"));
        /** 支付宝根证书路径，下载后保存位置的绝对路径 **/
        certAlipayRequest.setRootCertPath(environment.getProperty("ROOTCRETPATH"));
        /** 设置签名类型 **/
        certAlipayRequest.setSignType("RSA2");
        /** 设置请求格式，固定值json **/
        certAlipayRequest.setFormat("json");
        /** 设置编码格式 **/
        certAlipayRequest.setCharset("UTF-8");
        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", environment.getProperty("ALIPAYAPPID"), environment.getProperty("ALIPAYPRIVATEKEY"), "json", "utf-8", environment.getProperty("ALIPAYPUBLICKEY"), "RSA2");
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        String encode = URLEncoder.encode(attach);

        request.setBizContent("{" + "\"out_trade_no\":\""+orderNumber+"\"," +
                "\"total_amount\":"+amount+"," +
                "\"subject\":\"小华充电\"," +
                "\"timeout_express\":\"30m\"," +
                "\"passback_params\":\""+encode+"\"," +
                "\"buyer_id\":\""+openid+"\"" +
                "}");
        request.setNotifyUrl(environment.getProperty("ALIPAYPSERVERDOMAIN"));
        try {
        //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeCreateResponse response = alipayClient.certificateExecute(request);
            if(response.isSuccess()){
                String trade_no = response.getTradeNo();// 获取返回的tradeNO。
                return AjaxResult.success(trade_no);
            } else {
                return AjaxResult.error("生成订单失败，请稍后在试!");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return AjaxResult.error("生成订单失败，请稍后在试");
    }


    /**
     * 2      * 支付宝服务器异步通知url
     * 3      * @throws Exception
     * 4
     */
    @RequestMapping(value = "/notifyUrl")
    public String notifyUrl(HttpServletRequest request) throws Exception {
        logger.info("<<<<<<<<<<<<支付宝服务器异步通知>>>>>>>>>");
        Map<String, String> params = convertRequestParamsToMap(request);
        // 将异步通知中收到的待验证所有参数都存放到map中
        logger.info("<<<<<<<<<<<<params>>>>>>>>>"+params);
        logger.info("<<<<<<<<<<<<>>>>>>>>>");
        try{
            String publiccertpath = getAlipayPublicKey(environment.getProperty("PUBLICCERTPATH"));
            logger.info("<<<<<<<<<<<<支付宝公钥证书>>>>>>>>>"+publiccertpath);
            // 调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(params, publiccertpath, "utf-8", "RSA2");
            logger.info("<<<<<<<<<<<<验证签名>>>>>>>>>"+signVerified);
            if (signVerified) {
                //("支付宝回调签名认证成功");
                AlipayNotifyParam param = buildAlipayNotifyParam(params);
                String trade_status = param.getTradeStatus();
                // 支付成功
                if (trade_status.equals("TRADE_SUCCESS") || trade_status.equals("TRADE_FINISHED")) {
                    // 处理支付成功逻辑
                    try{
                        String passbackParams = param.getPassbackParams();
                        String tradeStatus = param.getTradeStatus();
                        if ("TRADE_SUCCESS".equals(tradeStatus)) {
                            // 业务参数主要转码回来
                            JSONObject jsonObject = JSON.parseObject(URLDecoder.decode(passbackParams));
                            String out_trade_no = jsonObject.getString("out_trade_no");
                            String transaction_id = jsonObject.getString("transaction_id");
                            paymentCallback(out_trade_no, transaction_id);
                        }
                    }catch (Exception e){
                        //("支付宝回调业务处理报错,params:" + paramsJson, e);
                    }
                }else{
                    //("没有处理支付宝回调业务，支付宝交易状态：{},params:{}",trade_status,paramsJson);
                }

                // 业务处理失败，可查看日志进行补偿，跟支付宝已经没多大关系。
                return "success";
            }else{
                return "failure";
            }
        }catch (Exception e){
            e.printStackTrace();
            //logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
            return "failure";
        }

    }


    //附加参数
    public String attachYu(String id, String money, String payStyle, String out_trade_no) {
        // 发送请求参数  业务参数
        StringBuilder attachSB = new StringBuilder();
        attachSB.append(",{\"customerId\":" + id);
        attachSB.append(",\"money\":\"" + money + "\"");
        attachSB.append(",\"out_trade_no\":\"" + out_trade_no + "\"}");
        String attach = attachSB.substring(1);
        return attach;
    }

    private AlipayNotifyParam buildAlipayNotifyParam(Map<String, String> params) {
        String json = JSON.toJSONString(params);
        return JSON.parseObject(json, AlipayNotifyParam.class);
    }
    // 将request中的参数转换成Map
    private Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();
        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;
            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }
        return retMap;
    }

    /**
     * 修改支付订单
     *
     * @param
     * @param
     * @return
     * @throws Exception
     */
    public void paymentCallback(String out_trade_no, String transaction_id) {
        //支付订单编号
        XhpcRechargeOrder xhpcRechargeOrder = iXhpcRechargeOrderService.infoRechargeOrderNumber(out_trade_no);
        if (StringUtils.isNotNull(xhpcRechargeOrder)) {
            //修改充值订单状态
            iXhpcRechargeOrderService.updateRechargeOrder(xhpcRechargeOrder.getRechargeOrderId(), StatusConstants.OPERATION_WX_TYPE, StatusConstants.RECHARGE_ORDER_STATUS_SUCCESS, transaction_id);
        }
        Map<String, Object> appUserInfo = xhpcUserAccountStatementMapper.appUserInfo(xhpcRechargeOrder.getUserId());
        if (StringUtils.isNotNull(appUserInfo)) {
            String balance = StringUtils.valueOf(appUserInfo.get("balance"));
            BigDecimal money = BigDecimal.valueOf(Double.valueOf(balance)).add(xhpcRechargeOrder.getAmount());
            //判断用户是否在充电中
            String serialMumber = xhpcUserAccountStatementMapper.getUserHistotyChargeOrder(xhpcRechargeOrder.getUserId());
            logger.info("<<<<<<<<<<<<充电终端>>>>>>>>>serialMumber："+serialMumber);
            if(!"".equals(serialMumber) && serialMumber !=null){
                //充电中
                postRefreshBalance(money, serialMumber);
            }
            //增加用户余额
            XhpcAppUser xhpcAppUser = new XhpcAppUser();
            xhpcAppUser.setAppUserId(xhpcRechargeOrder.getUserId());
            xhpcAppUser.setBalance(money);
            xhpcUserAccountStatementMapper.updateAppUserBalance(xhpcAppUser);
            XhpcUserAccountStatement xhpcUserAccountStatement = new XhpcUserAccountStatement();
            xhpcUserAccountStatement.setType(StatusConstants.FLOWING_WATER_RECHARGE_TYPE);
            xhpcUserAccountStatement.setRechargeOrderId(xhpcRechargeOrder.getRechargeOrderId());
            xhpcUserAccountStatement.setUserId(xhpcRechargeOrder.getUserId());
            xhpcUserAccountStatement.setAmount(xhpcRechargeOrder.getAmount());
            xhpcUserAccountStatement.setRemainingSum(xhpcAppUser.getBalance());
            xhpcUserAccountStatement.setCreateTime(new Date());
            xhpcUserAccountStatement.setRemark("支付宝充值订单！");
            xhpcUserAccountStatementMapper.insert(xhpcUserAccountStatement);
        }
    }

    private void postRefreshBalance(BigDecimal money, String serialMumber) {
        StartChargingData startChargingData =new StartChargingData();
        String su1 = serialMumber.substring(0, 14);
        String su2 = serialMumber.substring(14);
        startChargingData.setPileNo(su1);
        startChargingData.setGunId(su2);
        String s1 =money.multiply(new BigDecimal(100)).toString();
        startChargingData.setBalance(Double.valueOf(s1).intValue());
        R r = powerPileService.refreshBalance(startChargingData);
        logger.info("<<<<<<<<<<<<余额下发>>>>>>>>>");
        logger.info("<<<<<<<<<<<<"+r.getCode()+">>>>>>>>>");
        logger.info("<<<<<<<<<<<<"+r.getMsg()+">>>>>>>>>");

    }


    public static void main(String[] args) {
        try{

//            String st ="{gmt_create=2021-10-15 10:14:13, charset=UTF-8, seller_email=27555730@qq.com, subject=小华充电, sign=PNRU8Rck2aTVWqgoVOOsaZFujrlt7AQrsZKWw8S4RP7Ctehgj607PZ0j8364YLuIL9SKY1G7pPAP1Zfgur1uRw5CiqygqBkDl+jVu4Wh1BYUs8Qe0S5rKHGWk27uGi2gGdEvwCoPpzOnfHpGUbz3dhlqb03rkROAHHUNgOeKeMyzU5sfUB6z/tDpXoB3bcqZoEeaBba/mlu7L3QgqAXTRVLaE5tPntZfe5Ag/Sh3M9YX+07ktxA4khvCpRsB84yT3DTAKj8qY/IWnlsf4iUcU0A8GuGRAjkYNwadOIH3N/ngmS9LPkDME+TwoJ8F1gFpx6xbYSSbq8AtoGedujJXpA==, buyer_id=2088912814256712, invoice_amount=2.84, notify_id=2021101500222101424056715726105484, fund_bill_list=[{\"amount\":\"2.16\",\"fundChannel\":\"COUPON\"},{\"amount\":\"2.84\",\"fundChannel\":\"ALIPAYACCOUNT\"}], notify_type=trade_status_sync, trade_status=TRADE_SUCCESS, receipt_amount=5.00, buyer_pay_amount=5.00, app_id=2021002156615717, sign_type=RSA2, seller_id=2088631279527183, gmt_payment=2021-10-15 10:14:23, notify_time=2021-10-15 10:14:24, passback_params=%7B%22customerId%22%3A19%2C%22money%22%3A%225%22%2C%22out_trade_no%22%3A%22000000120211015101411117%22%7D, version=1.0, out_trade_no=000000120211015101411117, total_amount=5.00, trade_no=2021101522001456715750880678, auth_app_id=2021002156615717, buyer_logon_id=181****4652, point_amount=0.00}";
//            System.out.println("map:"+st);
//            String resultInfo=st.substring(1,st.length()-1);
//            //resultInfo=resultInfo.replace(", ","&");
//            System.out.println("resultInfo="+resultInfo);
//            //回调的待验签字符串
//            //String resultInfo = "gmt_create=2021-10-14 18:55:50&charset=UTF-8&seller_email=27555730@qq.com&subject=小华充电&sign=DN7OEd6MwL1d+RsevKOPD9XGGV4hJFZ/gKRuqh2wCIN9FWlutMp654XyTPCu1jOGYaCQkjycJiriq+Cxqp6bXa0bAEKdrl+3bqfE1Cx9YjL5nvgYLuhfhoH7rrFsJVBE92lh7O541f+w8HNrTSG5Xa6lUUuqb55MEHx2GKvAISM9BChSK279FvLQV7rhmhO840QIJCgQkwm6sueLg1tVnH9nkcd0YRrE924n+mYzdRAS6Ekq2MlE2vOjHslO796oIKY0EyHb4z6liSupkmiZgQ2v5DppXiS6+/H6uLyOBMhIgMdO9ZmYRkUtHkq7emYmvjFwR2lRdy/qqnGW3OFbGw==&buyer_id=2088912814256712&invoice_amount=5.00&notify_id=2021101400222185603056715724775024&fund_bill_list=[{\"amount\":\"5.00\",\"fundChannel\":\"ALIPAYACCOUNT\"}]&notify_type=trade_status_sync&trade_status=TRADE_SUCCESS&receipt_amount=5.00&buyer_pay_amount=5.00&app_id=2021002156615717&sign_type=RSA2&seller_id=2088631279527183&gmt_payment=2021-10-14 18:56:03&notify_time=2021-10-14 19:10:21&passback_params=%7B%22customerId%22%3A13%2C%22money%22%3A%225%22%2C%22out_trade_no%22%3A%22000000120211014185549114%22%7D&version=1.0&out_trade_no=000000120211014185549114&total_amount=5.00&trade_no=2021101422001456715747823733&auth_app_id=2021002156615717&buyer_logon_id=181****4652&point_amount=0.00";
//            String charset="utf-8";
//            //支付宝公钥证书
//            String alipayPublicCertPath="I:\\顶想\\充电桩\\支付宝\\10-13\\alipayCertPublicKey_RSA2.crt";
//            //签名方式
//            String sign_type="RSA2";
//            //对待签名字符串数据通过&进行拆分
//            String [] temp = resultInfo.split(", ");
//            LinkedHashMap<String, String> map =  new LinkedHashMap<String, String>();
//            //把拆分数据放在map集合内
//            for (int i = 0; i < temp.length; i++) {
//                String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
//                String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
//                for (int j = 0; j < arr.length; j++) {
//                    tempAagin[j] = arr[j];
//                }
//                map.put(tempAagin[0], tempAagin[1]);
//            }
//            System.out.println("map:"+map);
//            //验签方法
//            boolean signVerified= AlipaySignature.rsaCertCheckV1(map, alipayPublicCertPath, charset,sign_type);
//            if(signVerified){
//                // TODO 验签成功后
//                System.out.println("验签成功后:success");
//            }else{
//                System.out.println("验签失败后:fail");
//            }



        }catch (Exception e){
            e.printStackTrace();
        }

    }


    /**
     * 从公钥证书中提取公钥
     *
     * @param alipayPublicCertPath 公钥证书存放路径，例如:/home/admin/cert.crt
     * @return 公钥
     * @throws AlipayApiException
     */
    public static String getAlipayPublicKey(String alipayPublicCertPath) throws AlipayApiException {
        return AntCertificationUtil.getAlipayPublicKey(alipayPublicCertPath);
    }

}
