package com.xhpc.payment.controller;

import com.xhpc.common.api.PileOrderService;
import com.xhpc.common.api.PowerPileService;
import com.xhpc.common.api.UserTypeService;
import com.xhpc.common.core.annotation.NoRepeatSubmit;
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.utils.WXPayUtil;
import com.xhpc.common.core.web.domain.AjaxResult;
import com.xhpc.common.data.down.StartChargingData;
import com.xhpc.common.log.annotation.Log;
import com.xhpc.common.log.enums.BusinessType;
import com.xhpc.common.redis.service.RedisService;
import com.xhpc.common.security.service.TokenService;
import com.xhpc.common.util.UserTypeUtil;
import com.xhpc.payment.domain.XhpcAppInternetUser;
import com.xhpc.payment.domain.XhpcAppUser;
import com.xhpc.common.domain.XhpcRechargeOrder;
import com.xhpc.common.domain.XhpcSettingConfig;
import com.xhpc.payment.domain.XhpcUserAccountStatement;
import com.xhpc.payment.mapper.XhpcUserAccountStatementMapper;
import com.xhpc.payment.service.IXhpcCommonPayment;
import com.xhpc.payment.service.IXhpcRechargeOrderService;
import com.xhpc.payment.service.IXhpcRefundOrderService;
import com.xhpc.system.api.model.LoginUser;
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.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@RestController
@RequestMapping("/wx")
@Api(value = "微信支付接口", tags = "微信支付接口")
public class WxPaymentController {

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    @Autowired
    private IXhpcRechargeOrderService iXhpcRechargeOrderService;
    @Autowired
    private XhpcUserAccountStatementMapper xhpcUserAccountStatementMapper;
    @Autowired
    private IXhpcRefundOrderService iXhpcRefundOrderService;
    @Autowired
    private PowerPileService powerPileService;
    @Autowired
    private PileOrderService pileOrderService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private UserTypeService userTypeService;
    @Autowired
    private IXhpcCommonPayment xhpcCommonPayment;
    @Autowired
    private RedisService redisService;


    private static final Logger logger = LoggerFactory.getLogger(WxPaymentController.class);
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    @Log(title = "微信-支付", businessType = BusinessType.INSERT)
    @NoRepeatSubmit(lockTime = 3)
    @PostMapping("/payment")
    @ApiOperation(value = "微信支付")
    public 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元");
            }
            if(new BigDecimal(600).compareTo(new BigDecimal(amount))==-1){
                return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能大于600元");
            }
        }

        //用户信息id
        if(map.get("userId") ==null || "".equals(map.get("userId").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请在我的里面进行充值");
        }
        String userId = StringUtils.valueOf(map.get("userId"));

        LoginUser loginUser = tokenService.getLoginUser(servletRequest);
        Long userid = loginUser.getUserid();
        Integer userType = loginUser.getUserType();
        String tenantId = loginUser.getTenantId();

        if(UserTypeUtil.CUSTOMERS_TYPE.equals(userType)){
            return AjaxResult.error(HttpStatus.ERROR_STATUS, "大客户不支持充值,请让管理员在平台充值");
        }

        Map<String, Object> refundOrder = iXhpcRefundOrderService.getNotRefundOrder(userid,userType,tenantId);
        if (StringUtils.isNotNull(refundOrder)) {
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "用户存正在退款");
        }
        BigDecimal amount1 = new BigDecimal(amount).multiply(new BigDecimal(100));
        String orderNumber = StringUtils.numFormat(Long.parseLong(userId), 1, StatusConstants.FLOWING_WATER_RECHARGE_TYPE);
        if (amount1.compareTo(new BigDecimal(0.0))==0) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能为0");
        }
        XhpcSettingConfig xhpcSettingConfig = xhpcCommonPayment.getXhpcSettingConfigTenantId(UserTypeUtil.OPERATION_WX_TYPE, tenantId);
        if(xhpcSettingConfig ==null){
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "微信充值失败,继续充值请联系客服");
        }
        //生成充值订单
        XhpcRechargeOrder xhpcRechargeOrder = iXhpcRechargeOrderService.addRechargeOrder(userId, new BigDecimal(amount), "1", orderNumber,userType,null);
        //附加数据(否)
        String attach = attachYu(StringUtils.valueOf(xhpcRechargeOrder.getRechargeOrderId()), StringUtils.valueOf(amount), null, orderNumber);
        //商品描述(是)
        String body = "用户充值";
        //商户订单号(是)
        String outTradeNo = orderNumber;
        int Fee = amount1.intValue();
        //终端ip(是)
        String spbillCreateIp = getRemoteLoginUserIp(servletRequest);
        //交易类型(是)
        String tradeType = "JSAPI";
        Date date = new Date();
        //微信过期时间格式
        SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
        //过期时间半个小时
        Date expireTime = new Date(date.getTime() + StatusConstants.EXPIRE_TIME);
        String timeStr = format1.format(expireTime);
        //发送请求
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuffer result = new StringBuffer();
        try {
            URL realUrl = new URL(xhpcSettingConfig.getWxPaymentUrl());
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("Content-Type", "text/xml");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            out.print(createXMLParam(Fee, attach, tradeType, spbillCreateIp, outTradeNo, body, timeStr, xhpcSettingConfig.getWxCallbackUrl(), xhpcSettingConfig.getWxAppId(), xhpcSettingConfig.getWxMchId(), xhpcSettingConfig.getWxMchKey(), openid));
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应

            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
                System.out.println(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        //app
        Map<String, String> sign = createSign(result.toString(), Double.parseDouble(amount),xhpcSettingConfig.getWxMchKey());
        return AjaxResult.success(sign);
    }



    @Log(title = "欠费支付", businessType = BusinessType.INSERT)
    @NoRepeatSubmit(lockTime = 3)
    @PostMapping("/arrearsPayment")
    @ApiOperation(value = "欠费支付")
    public AjaxResult arrearsPayment(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, "充值金额不能为空");
        }

        //用户信息id
        if(map.get("userId") ==null || "".equals(map.get("userId").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请在我的里面进行充值");
        }
        String userId = StringUtils.valueOf(map.get("userId"));

        LoginUser loginUser = tokenService.getLoginUser(servletRequest);
        Long userid = loginUser.getUserid();
        Integer userType = loginUser.getUserType();
        String tenantId = loginUser.getTenantId();

        if(UserTypeUtil.CUSTOMERS_TYPE.equals(userType)){
            return AjaxResult.error(HttpStatus.ERROR_STATUS, "大客户不支持充值,请让管理员在平台充值");
        }

        Map<String, Object> refundOrder = iXhpcRefundOrderService.getNotRefundOrder(userid,userType,tenantId);
        if (StringUtils.isNotNull(refundOrder)) {
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "用户存正在退款");
        }
        BigDecimal amount1 = new BigDecimal(amount).multiply(new BigDecimal(100));
        String orderNumber = StringUtils.numFormat(Long.parseLong(userId), 1, StatusConstants.FLOWING_WATER_RECHARGE_TYPE);
        if (amount1.compareTo(new BigDecimal(0.0))==0) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能为0");
        }
        XhpcSettingConfig xhpcSettingConfig = xhpcCommonPayment.getXhpcSettingConfigTenantId(UserTypeUtil.OPERATION_WX_TYPE, tenantId);
        if(xhpcSettingConfig ==null){
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "微信充值失败,继续充值请联系客服");
        }
        //生成充值订单
        XhpcRechargeOrder xhpcRechargeOrder = iXhpcRechargeOrderService.addRechargeOrder(userId, new BigDecimal(amount), "1", orderNumber,userType,null);
        //附加数据(否)
        String attach = attachYu(StringUtils.valueOf(xhpcRechargeOrder.getRechargeOrderId()), StringUtils.valueOf(amount), null, orderNumber);
        //商品描述(是)
        String body = "用户充值";
        //商户订单号(是)
        String outTradeNo = orderNumber;
        int Fee = amount1.intValue();
        //终端ip(是)
        String spbillCreateIp = getRemoteLoginUserIp(servletRequest);
        //交易类型(是)
        String tradeType = "JSAPI";
        Date date = new Date();
        //微信过期时间格式
        SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
        //过期时间半个小时
        Date expireTime = new Date(date.getTime() + StatusConstants.EXPIRE_TIME);
        String timeStr = format1.format(expireTime);
        //发送请求
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuffer result = new StringBuffer();
        try {
            URL realUrl = new URL(xhpcSettingConfig.getWxPaymentUrl());
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("Content-Type", "text/xml");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            out.print(createXMLParam(Fee, attach, tradeType, spbillCreateIp, outTradeNo, body, timeStr, xhpcSettingConfig.getWxCallbackUrl(), xhpcSettingConfig.getWxAppId(), xhpcSettingConfig.getWxMchId(), xhpcSettingConfig.getWxMchKey(), openid));
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应

            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
                System.out.println(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        //app
        Map<String, String> sign = createSign(result.toString(), Double.parseDouble(amount),xhpcSettingConfig.getWxMchKey());
        return AjaxResult.success(sign);
    }



    /**
     * 生成签名
     *
     * @param result xml格式字符串
     * @return
     */
    public Map<String, String> createSign(String result, Double amount,String key) {
        try {
            Map<String, String> map = WXPayUtil.xmlToMap(result);
            String return_code = map.get("return_code");
            if ("FAIL".equals(return_code)) {
                return null;
            } else {
                //我这里是手动拼接的  可以使用微信具类生成签名
                String nonceStr = WXPayUtil.generateNonceStr();
                Map<String, String> map1 = new HashMap<>();
                map1.put("money", StringUtils.valueOf(amount));
                map1.put("appid", map.get("appid"));
                map1.put("prepayId", map.get("prepay_id"));
                map1.put("noncestr", nonceStr);
                map1.put("nonceStr", nonceStr + "\",\"packageValue\":" + "\"Sign=WXPay\"");
                map1.put("package", "Sign=WXPay");
                map1.put("partnerid", map.get("mch_id"));
                Long time = System.currentTimeMillis();
                String timeStr = time.toString().substring(0, time.toString().length() - 3);
                map1.put("timestamp", timeStr);
                map1.put("sign", map.get("sign"));
                map1.put("url", map.get("code_url"));
                map1.put("key", key);
                return map1;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成xml格式参数
     * 注释的是使用微信工具类生成的xml格式  添加参数时，按照abcd26个字母顺序添加
     *
     * @param total_fee    支付金额
     * @param attach       自定义参数
     * @param trade_type   交易类型
     * @param ip           终端ip地址
     * @param out_trade_no 交易订单号
     * @param body         交易信息
     * @param timeExpire   交易过期时间
     * @param WXNotifyUrl  微信支付回调地址
     * @param appid        应用ID
     * @param mch_id       商户号
     * @param key          添加key值
     * @return
     */
    public String createXMLParam(Integer total_fee, String attach, String trade_type, String ip, String out_trade_no, String body, String timeExpire, String WXNotifyUrl, String appid, String mch_id, String key, String openid) {
        String param = "";
        String nonce_str = generateNonceStr();
        String notify_url = WXNotifyUrl;
        String spbill_create_ip = ip;
        //应用ID
        param += "appid=" + appid;
        //附加数据  回调时可以获取
        param += "&attach=" + attach;
        //body 商品描述
        param += "&body=" + body;
        //商户号
        param += "&mch_id=" + mch_id;
        //随机字符串
        param += "&nonce_str=" + nonce_str;
        //回调地址
        param += "&notify_url=" + notify_url;
        if ("JSAPI".equals(trade_type)) {
            //用户openid
            param += "&openid=" + openid;
        }
        //商户订单号
        param += "&out_trade_no=" + out_trade_no;
        //终端IP
        param += "&spbill_create_ip=" + spbill_create_ip;
        //交易结束时间
        param += "&time_expire=" + timeExpire;
        //总金额
        param += "&total_fee=" + total_fee;
        //支付类型
        param += "&trade_type=" + trade_type;
        //生成签名  添加key值
        String stringSignTemp = param + "&key=" + key;
        //签名  不参与签名  默认MD5算法
        String sign = StringUtils.md5(stringSignTemp);
        if(sign.length() !=32){
            sign="0"+sign;
        }
        String xmlString = "<xml>\n" +
                "   <appid>" + appid + "</appid>\n" +
                "   <attach>" + attach + "</attach>\n" +
                "   <body>" + body + "</body>\n" +
                "   <mch_id>" + mch_id + "</mch_id>\n" +
                "   <nonce_str>" + nonce_str + "</nonce_str>\n" +
                "   <notify_url>" + notify_url + "</notify_url>\n";
        if ("JSAPI".equals(trade_type)) {
            xmlString += "   <openid>" + openid + "</openid>\n";
        }
        xmlString +=
                "   <out_trade_no>" + out_trade_no + "</out_trade_no>\n" +
                        "   <spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>\n" +
                        "   <time_expire>" + timeExpire + "</time_expire>\n" +
                        "   <total_fee>" + total_fee + "</total_fee>\n" +
                        "   <trade_type>" + trade_type + "</trade_type>\n";

        if ("MWEB".equals(trade_type)) {
            xmlString += "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"https://pay.qq.com\",\"wap_name\": \"腾讯充值\"}}";
        }


        xmlString +=    "   <sign>" + sign + "</sign>\n" +
                "</xml> ";

        System.out.println("============weixin==xmlString================");
        System.out.println("============weixin==xmlString================"+xmlString);
        System.out.println("============weixin==xmlString================");

        return xmlString;
    }

    //附加参数
    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;
    }

    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    //获取终端ip
    public String getRemoteLoginUserIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        System.out.println("THE REAL IPS IS:" + ip);
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        return ip;
    }

    /**
     * 回调Api
     */
    @RequestMapping("/test")
    public void test() {
        paymentCallback("001000020240320230930112", "4200002216202403204978228278");
    }

    /**
     * 修改支付订单
     *
     * @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)) {
            if(xhpcRechargeOrder.getStatus() == 0){

                if(xhpcRechargeOrder.getSource()==1){
                    //修改充值订单状态
                    Long userId = xhpcRechargeOrder.getUserId();
                    Integer source = xhpcRechargeOrder.getSource();
                    String tenantId = xhpcRechargeOrder.getTenantId();
                    R user = userTypeService.getUser(null,userId, source, null, tenantId);
                    if(user !=null && user.getData() !=null){
                        Map<String, Object> map = (Map<String, Object>)user.getData();
                        String balance = StringUtils.valueOf(map.get("balance"));
                        BigDecimal money = BigDecimal.valueOf(Double.valueOf(balance)).add(xhpcRechargeOrder.getAmount());
                        iXhpcRechargeOrderService.updateRechargeOrder(xhpcRechargeOrder.getRechargeOrderId(), StatusConstants.OPERATION_WX_TYPE, StatusConstants.RECHARGE_ORDER_STATUS_SUCCESS, transaction_id);
                        if(UserTypeUtil.INTERNET_TYPE.equals(source)){
                            //增加用户余额
                            XhpcAppInternetUser xhpcAppUser = new XhpcAppInternetUser();
                            xhpcAppUser.setAppInternetUserId(xhpcRechargeOrder.getUserId());
                            xhpcAppUser.setBalance(money);
                            xhpcUserAccountStatementMapper.updateAppInternetUserBalance(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("微信充值订单！");
                            xhpcUserAccountStatement.setSource(source);
                            xhpcUserAccountStatementMapper.insert(xhpcUserAccountStatement);
                            //启动充电
                            pileOrderService.cycStartUp(userId,xhpcRechargeOrder.getSerialNumber(),1,1,money,map.get("phone").toString(),map.get("plateNum").toString());

                        }
                    }

                }else{
                    //修改充值订单状态
                    iXhpcRechargeOrderService.updateRechargeOrder(xhpcRechargeOrder.getRechargeOrderId(), StatusConstants.OPERATION_WX_TYPE, StatusConstants.RECHARGE_ORDER_STATUS_SUCCESS, transaction_id);

                    Long userId = xhpcRechargeOrder.getUserId();
                    Integer source = xhpcRechargeOrder.getSource();
                    String tenantId = xhpcRechargeOrder.getTenantId();
                    R user = userTypeService.getUser(null,userId, source, null, tenantId);
                    if(user !=null && user.getData() !=null){
                        Map<String, Object> map = (Map<String, Object>)user.getData();
                        Integer sunchaSwitch = Integer.valueOf(map.get("sunchaSwitch").toString());
                        if(sunchaSwitch==0){
                            String balance = StringUtils.valueOf(map.get("balance"));
                            BigDecimal money = BigDecimal.valueOf(Double.valueOf(balance)).add(xhpcRechargeOrder.getAmount());
                            //判断用户是否在充电中
                            String serialMumber = xhpcUserAccountStatementMapper.getUserHistotyChargeOrder(xhpcRechargeOrder.getUserId(),source,tenantId);
                            logger.info("<<<<<<<<<<<<充电终端>>>>>>>>>serialMumber："+serialMumber);
                            if(!"".equals(serialMumber) && serialMumber !=null){
                                //充电中
                                postRefreshBalance(money, serialMumber);
                            }
                            if(UserTypeUtil.USER_TYPE.equals(source)){
                                //增加用户余额
                                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);
                            }else{
                                //增加用户余额
                                userTypeService.insertUserBalance(xhpcRechargeOrder.getAmount(),userId,source,tenantId, UserTypeUtil.RECHARGE_WX,UserTypeUtil.INSERT_BALANCE,null,xhpcRechargeOrder.getRechargeOrderId());
                            }
                        }else{
                            String balance = StringUtils.valueOf(map.get("balance"));
                            BigDecimal aBigDecimal = xhpcRechargeOrder.getAmount().divide(new BigDecimal(2)).setScale(0, BigDecimal.ROUND_UP);
                            BigDecimal bBigDecimal =xhpcRechargeOrder.getAmount().subtract(aBigDecimal);
                            BigDecimal aBalance = new BigDecimal(map.get("aBalance").toString()).add(aBigDecimal);
                            BigDecimal bBalance = new BigDecimal(map.get("bBalance").toString()).add(bBigDecimal);
                            String userType =UserTypeUtil.USER;
                            if(UserTypeUtil.COMMUNIT_TYPE==xhpcRechargeOrder.getSource()){
                                userType =UserTypeUtil.COMMUNIT;
                            }else if(UserTypeUtil.CUSTOMERS_TYPE==xhpcRechargeOrder.getSource()){
                                userType =UserTypeUtil.CUSTOMERS;
                            }
                            String key = "user:" + xhpcRechargeOrder.getUserId() + userType + ".order";

                            Map<String, Object> cacheMap = redisService.getCacheMap(key);
                            //判断用户是否在充电中
                            String serialMumberA = xhpcUserAccountStatementMapper.getUserHistotyChargeOrderSuncha(xhpcRechargeOrder.getUserId(),source,tenantId,1);
                            if(!"".equals(serialMumberA) && serialMumberA !=null){
                                //充电中
                                cacheMap.put("aBalance", aBalance.multiply(new BigDecimal(100)));
                                redisService.setCacheMap(key,cacheMap);
                                postRefreshBalance(aBalance, serialMumberA);
                            }
                            String serialMumberB = xhpcUserAccountStatementMapper.getUserHistotyChargeOrderSuncha(xhpcRechargeOrder.getUserId(),source,tenantId,2);
                            if(!"".equals(serialMumberB) && serialMumberB !=null){
                                //充电中
                                cacheMap.put("bBalance", bBalance.multiply(new BigDecimal(100)));
                                redisService.setCacheMap(key,cacheMap);
                                postRefreshBalance(bBalance, serialMumberB);
                            }

                            BigDecimal money = BigDecimal.valueOf(Double.valueOf(balance)).add(xhpcRechargeOrder.getAmount());
                            if(UserTypeUtil.USER_TYPE.equals(source)){
                                //增加用户余额
                                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);
                            }else{
                                //增加用户余额
                                userTypeService.insertUserBalance(xhpcRechargeOrder.getAmount(),userId,source,tenantId, UserTypeUtil.RECHARGE_WX,UserTypeUtil.INSERT_BALANCE,null,xhpcRechargeOrder.getRechargeOrderId());
                            }

                        }
                    }
                }
            }
        }
    }

    private void postRefreshBalance(BigDecimal money, String serialMumber) {
        StartChargingData startChargingData =new StartChargingData();
        String su1 = serialMumber.substring(0, 14);
        String su2 = serialMumber.substring(14);
        logger.info("<<<<<<<<<<<<su1>>>>>>>>>"+su1);
        logger.info("<<<<<<<<<<<<su2>>>>>>>>>"+su2);
        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("<<<<<<<<<<<<余额下发>>>>>>>>>"+s1);
        logger.info("<<<<<<<<<<<<"+r.getCode()+">>>>>>>>>");
        logger.info("<<<<<<<<<<<<"+r.getMsg()+">>>>>>>>>");

        //修改订单充电下发的金额
        Map<String, Object> cacheMap = redisService.getCacheMap("order:"+serialMumber);

        if(cacheMap.get("initBalance") !=null){
            cacheMap.put("initBalance",Double.valueOf(money.multiply(new BigDecimal(10000)).toString()).intValue());
            redisService.setCacheMap("order:"+serialMumber,cacheMap);
            redisService.setCacheObject("YE"+serialMumber,money);
        }

        if(r.getCode() !=200){
            //创建定时任务

        }
    }

    /**
     * 回调Api
     */
    @RequestMapping("/paymentCallback")
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
        try{
            System.out.println("============weixin==回调Api======开始==========");
            readWriteLock.writeLock().lock();//取
            try {
                ServletInputStream in = null;
                BufferedReader reader = null;
                StringBuilder content = new StringBuilder();
                try {
                    in = request.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
                    String itemStr = "";// 作为输出字符串的临时串，用于判断是否读取完毕
                    while (null != (itemStr = reader.readLine())) {
                        content.append(itemStr);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (null != reader)
                            reader.close();
                        if (null != in)
                            in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //将xml转换成map
                Map<String, String> map = WXPayUtil.xmlToMap(content.toString());
                String return_code = map.get("return_code");
                //自定义参数  为json格式的字符串
                //如果返回成功
                if ("SUCCESS".equals(return_code)) {
                    //将自定义参数转换成JSONObject对象，处理业务逻辑
                    String out_trade_no = map.get("out_trade_no");
                    String transaction_id = map.get("transaction_id");
                    paymentCallback(out_trade_no, transaction_id);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/xml; charset=utf-8");
            PrintWriter out = null;
            try {
                out = response.getWriter();
                out.print("<xml>\n" +
                        "  <return_code><![CDATA[SUCCESS]]></return_code>\n" +
                        "  <return_msg><![CDATA[OK]]></return_msg>\n" +
                        "</xml>\n");
                out.close();
                return null;
            } catch (IOException e) {
                e.printStackTrace();
            }
            Thread.sleep(500);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            readWriteLock.writeLock().unlock();//释放锁
        }


        return null;
    }



    @Log(title = "川逸充-微信-支付", businessType = BusinessType.INSERT)
    //@NoRepeatSubmit(lockTime = 3)
    @PostMapping("/cycPayment")
    @ApiOperation(value = "微信支付")
    public AjaxResult cycPayment(HttpServletRequest servletRequest, @RequestBody Map<String, Object> map) throws Exception {

        System.out.println("=============map===============");
        System.out.println("=============map==============="+map.toString());
        System.out.println("=============map===============");
        //总金额(是)订单总金额，单位为分
        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元");
            }
            if(new BigDecimal(600).compareTo(new BigDecimal(amount))==-1){
                return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能大于600元");
            }
        }
        //用户信息id
        if(map.get("userId") ==null || "".equals(map.get("userId").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请重新进入启动充电页面");
        }
        if(map.get("serialNumber") ==null || "".equals(map.get("serialNumber").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请重新进入启动充电页面");
        }
        if(map.get("userType") ==null || "".equals(map.get("userType").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请重新进入启动充电页面");
        }
        if(map.get("tenantId") ==null || "".equals(map.get("tenantId").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请重新进入启动充电页面");
        }
        if(map.get("plateNum") ==null || "".equals(map.get("plateNum").toString())){
            return AjaxResult.error(HttpStatus.NOT_NULL, "请重新进入启动充电页面");
        }
        Long userId = Long.valueOf(map.get("userId").toString());
        Integer userType = Integer.parseInt(map.get("userType").toString());
        String tenantId = StringUtils.valueOf(map.get("tenantId"));
        String serialNumber = StringUtils.valueOf(map.get("serialNumber"));
        if(UserTypeUtil.INTERNET_TYPE.equals(userType.toString())){
            return AjaxResult.error(HttpStatus.ERROR_STATUS, "只支持川逸充用户充值");
        }

        XhpcAppInternetUser xhpcAppUser = new XhpcAppInternetUser();
        xhpcAppUser.setAppInternetUserId(userId);
        xhpcAppUser.setPlateNum(map.get("plateNum").toString());
        xhpcUserAccountStatementMapper.updateAppInternetUserBalance(xhpcAppUser);

//        Map<String, Object> refundOrder = iXhpcRefundOrderService.getNotRefundOrder(userId,userType,tenantId);
//        if (StringUtils.isNotNull(refundOrder)) {
//            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "用户存正在退款");
//        }

        //是否在充电
        int i = iXhpcRefundOrderService.countXhpcRealTimeOrder(userId, userType, tenantId);
        if (i>0) {
            return AjaxResult.error(1102, "车辆正在充电,请查询车辆充电信息");
        }

        BigDecimal amount1 = new BigDecimal(amount).multiply(new BigDecimal(100));
        String orderNumber = StringUtils.numFormat(userId, 1, StatusConstants.FLOWING_WATER_RECHARGE_TYPE);
        if (amount1.compareTo(new BigDecimal(0.0))==0) {
            return AjaxResult.error(HttpStatus.NOT_NULL, "充值金额不能为0");
        }
        XhpcSettingConfig xhpcSettingConfig = xhpcCommonPayment.getXhpcSettingConfigTenantId(UserTypeUtil.OPERATION_WX_TYPE, tenantId);
        if(xhpcSettingConfig ==null){
            return AjaxResult.error(HttpStatus.ALREADY_EXISTING, "微信充值失败,继续充值请联系客服");
        }
        //生成充值订单
        XhpcRechargeOrder xhpcRechargeOrder = iXhpcRechargeOrderService.addRechargeOrder(userId+"", new BigDecimal(amount), "1", orderNumber,userType,serialNumber);
        //附加数据(否)
        String attach = attachYu(StringUtils.valueOf(xhpcRechargeOrder.getRechargeOrderId()), StringUtils.valueOf(amount), null, orderNumber);
        //商品描述(是)
        String body = "用户充值";
        //商户订单号(是)
        String outTradeNo = orderNumber;
        int Fee = amount1.intValue();
        //终端ip(是)
        String spbillCreateIp = getRemoteLoginUserIp(servletRequest);
        //交易类型(是)
        String tradeType = "MWEB";
        Date date = new Date();
        //微信过期时间格式
        SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
        //过期时间半个小时
        Date expireTime = new Date(date.getTime() + StatusConstants.EXPIRE_TIME);
        String timeStr = format1.format(expireTime);
        //发送请求
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuffer result = new StringBuffer();
        try {
            URL realUrl = new URL(xhpcSettingConfig.getWxPaymentUrl());
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("Content-Type", "text/xml");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            out.print(createXMLParam(Fee, attach, tradeType, spbillCreateIp, outTradeNo, body, timeStr, xhpcSettingConfig.getWxCallbackUrl(), xhpcSettingConfig.getWxAppId(), xhpcSettingConfig.getWxMchId(), xhpcSettingConfig.getWxMchKey(), ""));
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应

            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
                System.out.println(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        //app
        Map<String, String> sign = cycCreateSign(result.toString());

        if(sign!=null && sign.get("mwebUrl") !=null){
            return AjaxResult.success(sign);
        }
        return AjaxResult.error("支付失败，请重新进行入");
    }

    /**
     * H5解析微信返回数据
     *
     * @param result xml格式字符串
     * @return
     */
    public Map<String, String> cycCreateSign(String result) {
        try {
            Map<String, String> map = WXPayUtil.xmlToMap(result);
            String return_code = map.get("return_code");
            if ("FAIL".equals(return_code)) {
                return null;
            } else {
                Map<String, String> map1 = new HashMap<>();
                if("SUCCESS".equals(map.get("result_code"))){
                    map1.put("tradeType", map.get("trade_type"));
                    map1.put("prepayId", map.get("prepay_id"));
                    map1.put("mwebUrl", map.get("mweb_url"));
                }
                System.out.println("====================== H5解析微信返回数据============================");
                System.out.println("====================== H5解析微信返回数据==============map1=============="+map1.toString());
                System.out.println("====================== H5解析微信返回数据============================");
                return map1;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
