package com.jpsoft.shinestar.modules.pay.weixin;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.jfinal.kit.StrKit;
import com.jpsoft.shinestar.modules.base.entity.*;
import com.jpsoft.shinestar.modules.base.service.*;
import com.jpsoft.shinestar.modules.business.entity.BillPush;
import com.jpsoft.shinestar.modules.business.service.BillPushService;
import com.jpsoft.shinestar.modules.common.dto.MessageResult;
import com.jpsoft.shinestar.modules.common.service.IRedisService;
import com.jpsoft.shinestar.modules.common.utils.ParkApiUtil;
import com.jpsoft.shinestar.modules.pay.properties.WxJpsoftProperties;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 墨鱼_mo
 * @date 2019-11-26 10:35
 */

@RequestMapping("/wxPay")
@RestController
@Slf4j
public class WxPayController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private WxJpsoftProperties wxJpsoftProperties;


    @Value("${jwt.secret}")
    private String jwtSecret;

    @Autowired
    private BillPushService billPushService;

    @Autowired
    private PersonPopedomService personPopedomService;

    @Autowired
    private RechargeRecordService rechargeRecordService;

    @Autowired
    private ParkingInfoService parkingInfoService;

    @Autowired
    private PersonRoleIconService personRoleIconService;

    @Autowired
    private PersonInfoService personInfoService;

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private ElectricClientInfoService electricClientInfoService;

    @Autowired
    private ParkingRecordService parkingRecordService;

    @Autowired
    private CompanyPaymentInfoService companyPaymentInfoService;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private ParkApiUtil parkApiUtil;

    @Autowired
    private ParkingDeviceService parkingDeviceService;

    @ApiOperation(value = "微信JSAPI支付")
    @GetMapping("/webPay")
    public MessageResult webPay(String recordId, String openId) {
        MessageResult msgResult = new MessageResult<>();
        try {
            RechargeRecord rechargeRecord = rechargeRecordService.get(recordId);

            rechargeRecord.setOpenId(openId);
            rechargeRecord.setUpdateTime(new Date());

            rechargeRecordService.update(rechargeRecord);

            if (rechargeRecord == null) {
                throw new Exception("订单不存在");
            }
            if (StrUtil.isBlank(rechargeRecord.getOpenId())) {
                throw new Exception("openId不存在");
            }
            if (rechargeRecord.getBuyAmount().compareTo(BigDecimal.ZERO) != 1) {
                throw new Exception("金额有误");
            }
            if (rechargeRecord.getPaymentStatus().equals("20")) {
                throw new Exception("订单已支付");
            }

            //金额处理
            int wxTotalTee = rechargeRecord.getBuyAmount().multiply(new BigDecimal(100)).intValue();
            Map<String, String> params = UnifiedOrderModel
                    .builder()
                    .appid(wxJpsoftProperties.getAppId())
                    .mch_id(wxJpsoftProperties.getMchId())
                    .sub_mch_id(wxJpsoftProperties.getSubMchId())
                    .nonce_str(WxPayKit.generateStr())
                    .body(rechargeRecord.getProductTheme())
                    .out_trade_no(rechargeRecord.getSerialNumber())
                    .total_fee(String.valueOf(wxTotalTee))
                    .spbill_create_ip(wxJpsoftProperties.getIp())
                    .notify_url(wxJpsoftProperties.getNotifyUrl())
                    .trade_type(TradeType.JSAPI.getTradeType())
                    .openid(rechargeRecord.getOpenId())
                    .build()
                    .createSign(wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            String xmlResult = WxPayApi.pushOrder(false, params);
            logger.info(xmlResult);

            Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
            String returnCode = resultMap.get("return_code");
            String returnMsg = resultMap.get("return_msg");
            if (!WxPayKit.codeIsOk(returnCode)) {
                logger.error(returnCode);
                throw new Exception(returnMsg);
            }
            String resultCode = resultMap.get("result_code");
            if (!WxPayKit.codeIsOk(resultCode)) {
                String errCode = resultMap.get("err_code_des");
                logger.error(errCode);
                throw new Exception(errCode);
            }

            // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回

            String prepayId = resultMap.get("prepay_id");

            Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxJpsoftProperties.getAppId(),
                    wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            msgResult.setData(packageParams);
            msgResult.setResult(true);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            msgResult.setResult(false);
            msgResult.setMessage(e.getMessage());
        }
        return msgResult;
    }

    @ApiOperation(value = "停车微信JSAPI支付")
    @PostMapping("/parkingWxPay")
    public MessageResult parkingWxPay(String id, String openId) {
        MessageResult msgResult = new MessageResult<>();
        try {
            if (StrUtil.isBlank(openId)) {
                throw new Exception("openId不存在");
            }
            if (StrUtil.isBlank(id)) {
                throw new Exception("订单不存在");
            }

            ParkingRecord parkingRecord = parkingRecordService.get(id);

            parkingRecord.setUpdateTime(new Date());
            parkingRecord.setOpenId(openId);

            parkingRecordService.update(parkingRecord);

            if (parkingRecord == null) {
                throw new Exception("订单不存在");
            }

            if (parkingRecord.getPayAmount().compareTo(BigDecimal.ZERO) != 1) {
                throw new Exception("金额有误");
            }
            if (parkingRecord.getPayStatus().equals("20")) {
                throw new Exception("订单已支付");
            }

            ParkingInfo parkingInfo = parkingInfoService.findByParkId(parkingRecord.getParkId());
            CompanyPaymentInfo companyPaymentInfo = companyPaymentInfoService.findByCompanyId(parkingInfo.getCompanyId());
            if (companyPaymentInfo == null) {
                throw new Exception("该公司未配置收费账户");
            }


            //金额处理
            int wxTotalTee = parkingRecord.getPayAmount().multiply(new BigDecimal(100)).intValue();
            Map<String, String> params = UnifiedOrderModel
                    .builder()
                    .appid(companyPaymentInfo.getAppId())
                    //       .appid(companyPaymentInfo.getSubAppId())
                    //      .mch_id(companyPaymentInfo.getSubMchId())
                    .mch_id(companyPaymentInfo.getMchId())
                    .sub_mch_id(companyPaymentInfo.getSubMchId())
                    //      .sub_appid(companyPaymentInfo.getSubAppId())
                    .nonce_str(WxPayKit.generateStr())
                    .body(parkingRecord.getProductTheme())
                    .out_trade_no(parkingRecord.getSerialNumber())
                    .total_fee(String.valueOf(wxTotalTee))
                    .spbill_create_ip(wxJpsoftProperties.getIp())
                    .notify_url(companyPaymentInfo.getParkingWechatNotifyUrl())
                    .trade_type(TradeType.JSAPI.getTradeType())
                    .sub_openid(parkingRecord.getOpenId())
                   //  .openid(parkingRecord.getOpenId())
                    .build()
                    //    .createSign("jzjdwy11111111111111111111111111", SignType.HMACSHA256);
                    .createSign(wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            String xmlResult = WxPayApi.pushOrder(false, params);
            logger.info(xmlResult);

            Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
            String returnCode = resultMap.get("return_code");
            String returnMsg = resultMap.get("return_msg");
            if (!WxPayKit.codeIsOk(returnCode)) {
                logger.error(returnCode);
                throw new Exception(returnMsg);
            }
            String resultCode = resultMap.get("result_code");
            if (!WxPayKit.codeIsOk(resultCode)) {
                String errCode = resultMap.get("err_code_des");
                logger.error(errCode);
                throw new Exception(errCode);
            }

            // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回

            String prepayId = resultMap.get("prepay_id");

            Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxJpsoftProperties.getAppId(),
                    wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            msgResult.setData(packageParams);
            msgResult.setResult(true);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            msgResult.setResult(false);
            msgResult.setCode(400);
            msgResult.setMessage(e.getMessage());
        }
        return msgResult;
    }


    @RequestMapping(value = "/parkingWxPayNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String parkingWxPayNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.warn("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");
        String outTradeNo = params.get("out_trade_no");
        String payTimeStr = params.get("time_end");
        Date payTime = DateUtil.parse(payTimeStr);

        // 注意此处签名方式需与统一下单的签名类型一致 WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()
        if (WxPayKit.verifyNotify(params, wxJpsoftProperties.getMchKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息

                try {
                    ParkingRecord parkingRecord = parkingRecordService.findBySerialNumber(outTradeNo);
                    if (parkingRecord == null) {
                        throw new Exception("支付已完成，但未找到此订单号的流水");
                    }

                    parkingRecord.setUpdateTime(new Date());
                    parkingRecord.setUpdateBy(params.get("openid"));
                    parkingRecord.setPayType("wechat");
                    parkingRecord.setPayStatus(20);
                    parkingRecord.setTransactionNumber(params.get("transaction_id"));
                    parkingRecord.setPaymentTime(payTime);
                    parkingRecordService.update(parkingRecord);


                    //异步通知停车设备
                //    new Thread(()->{
                        try {
                            parkingRecordService.payNotify(parkingRecord.getId());
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                        }
              //      }).start();

                    // 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    @ApiOperation(value = "微信JSAPI支付公用方法")
    @GetMapping("/wxJsapiPay")
    public MessageResult wxJsapiPay(String orderId, String popularizePersonId) {
        MessageResult msgResult = new MessageResult<>();
        try {
            OrderInfo orderInfo = orderInfoService.get(orderId);

            if (orderInfo == null) {
                throw new Exception("订单不存在");
            }

            orderInfo.setPopularizePersonId(popularizePersonId);
            orderInfoService.update(orderInfo);


            String subMchId = wxJpsoftProperties.getSubMchId();
            //查询账单收款账户
            BillPush billPush = billPushService.findByOrderId(orderId);
            if (billPush != null) {
                CompanyPaymentInfo companyPaymentInfo = companyPaymentInfoService.get(Long.valueOf(billPush.getCollectionAccountId()));

                if (companyPaymentInfo != null) {
                    subMchId = companyPaymentInfo.getSubMchId();
                }
            }

            PersonInfo personInfo = personInfoService.get(orderInfo.getPersonId());

            if (personInfo == null) {
                throw new Exception("订单支付人不存在");
            }

            if (StrUtil.isBlank(personInfo.getOpenId())) {
                throw new Exception("openId不存在");
            }
            if (orderInfo.getTotalFee().compareTo(BigDecimal.ZERO) != 1) {
                throw new Exception("金额有误");
            }
            if (orderInfo.getPayStatus() != 10) {
                throw new Exception("订单状态有误");
            }
            String outOrderNo = orderInfo.getOutOrderNo();
            if (StringUtils.isNotBlank(wxJpsoftProperties.getUrlKey()) && !outOrderNo.contains(wxJpsoftProperties.getUrlKey())) {
                outOrderNo = wxJpsoftProperties.getUrlKey() + outOrderNo;
                orderInfo.setOutOrderNo(outOrderNo);
                orderInfoService.update(orderInfo);
            }

            //金额处理
            int wxTotalTee = orderInfo.getTotalFee().multiply(new BigDecimal(100)).intValue();
            Map<String, String> params = UnifiedOrderModel
                    .builder()
                    .appid(wxJpsoftProperties.getAppId())
                    .mch_id(wxJpsoftProperties.getMchId())
                    .sub_mch_id(subMchId)
                    //     .sub_appid(wxConfig.getAppId())
                    .nonce_str(WxPayKit.generateStr())
                    .body(orderInfo.getBody())
                    .out_trade_no(orderInfo.getOutOrderNo())
                    .total_fee(String.valueOf(wxTotalTee))
                    .spbill_create_ip(wxJpsoftProperties.getIp())
                    .notify_url(wxJpsoftProperties.getNotifyUrl())
                    .trade_type(TradeType.JSAPI.getTradeType())
                    .sub_openid(personInfo.getOpenId())
                    //    .openid(orderInfo.getOpenId())
                    .build()
                    .createSign(wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            String xmlResult = WxPayApi.pushOrder(false, params);

            Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
            String returnCode = resultMap.get("return_code");
            String returnMsg = resultMap.get("return_msg");
            if (!WxPayKit.codeIsOk(returnCode)) {
                logger.error(returnCode);
                throw new Exception(returnMsg);
            }
            String resultCode = resultMap.get("result_code");
            if (!WxPayKit.codeIsOk(resultCode)) {
                String errCode = resultMap.get("err_code_des");
                logger.error(errCode);
                throw new Exception(errCode);
            }

            // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回

            String prepayId = resultMap.get("prepay_id");

            Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxJpsoftProperties.getAppId(),
                    wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            msgResult.setData(packageParams);
            msgResult.setResult(true);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            msgResult.setResult(false);
            msgResult.setMessage(e.getMessage());
        }
        return msgResult;
    }

    @RequestMapping(value = "/wxJsapiPayNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String wxJsapiPayNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        logger.warn("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");
        String outTradeNo = params.get("out_trade_no");
        String payTimeStr = params.get("time_end");
        Date payTime = DateUtil.parse(payTimeStr);

        // 注意此处签名方式需与统一下单的签名类型一致 WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()
        if (WxPayKit.verifyNotify(params, wxJpsoftProperties.getMchKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息

                try {
                    OrderInfo orderInfo = orderInfoService.findByOutOrderNo(outTradeNo);
                    if (orderInfo == null) {
                        throw new Exception("支付已完成，但未找到此订单号的流水");
                    }
                    if (orderInfo.getTotalFee().multiply(new BigDecimal(100)).compareTo(new BigDecimal(params.get("total_fee"))) != 0) {
                        throw new Exception("支付金额与系统金额不一致");
                    }

                    orderInfo.setUpdateTime(new Date());
                    orderInfo.setUpdateBy(params.get("openid"));
                    orderInfo.setPayName("wechat");
                    orderInfo.setPayStatus(20);
                    orderInfo.setPayFee(new BigDecimal(params.get("total_fee")).divide(new BigDecimal(100)));
                    orderInfo.setTransactionId(params.get("transaction_id"));
                    orderInfo.setPayTime(payTime);
                    orderInfoService.update(orderInfo);
                    //    orderLogService.insert2(new OrderLog(orderInfo.getId(), "支付完成", orderInfo.getCreateBy()));

                    new Thread(() -> {
                        try {
                            //根据订单类型做各自处理
                            orderInfoService.orderNotifyLogical(orderInfo);
                        } catch (Exception ex) {
                            log.error(ex.getMessage(), ex);

                           /* SysLog sysLog = new SysLog();
                            sysLog.setRemark(ex.getMessage());
                            sysLog.setData(orderInfo.toString());
                            sysLog.setPointcut("支付");
                            sysLog.setCreateTime(new Date());
                            sysLogService.insert(sysLog);*/
                        }

                        try {

                            log.warn("通知财务人员钱已到账");
                            //支付成功向收款人发送消息
                            BillPush billPush = billPushService.findByOrderId(orderInfo.getId());
                            billPushService.sendAccountRemind(billPush);
                        } catch (Exception ex) {
                            log.error(ex.getMessage(), ex);
                        }
                    }).start();

                    // 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    return WxPayKit.toXml(xml);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    e.printStackTrace();
                }
            }
        }

        return null;
    }


    @ApiOperation(value = "微信扫码支付功能")
    @GetMapping("/wxNativePay")
    @ResponseBody
    public MessageResult wxNativePay(HttpServletRequest request, HttpServletResponse response,
                                     @RequestParam("orderId") String orderId) {

        MessageResult msgResult = new MessageResult<>();

        try {


            if (StrKit.isBlank(orderId)) {
                throw new Exception("订单id为空");
            }
            OrderInfo orderInfo = orderInfoService.get(orderId);

            if (orderInfo.getPayStatus() != 10) {
                throw new Exception("订单支付状态异常");
            }

            String subMchId = wxJpsoftProperties.getSubMchId();
            //查询账单收款账户
            BillPush billPush = billPushService.findByOrderId(orderId);
            if (billPush != null) {
                CompanyPaymentInfo companyPaymentInfo = companyPaymentInfoService.get(Long.valueOf(billPush.getCollectionAccountId()));

                if (companyPaymentInfo != null) {
                    subMchId = companyPaymentInfo.getSubMchId();
                }
            }

            //金额处理
            int wxTotalTee = orderInfo.getTotalFee().multiply(new BigDecimal(100)).intValue();

            Map<String, String> params = UnifiedOrderModel
                    .builder()
                    .appid(wxJpsoftProperties.getAppId())
                    .mch_id(wxJpsoftProperties.getMchId())
                    .sub_mch_id(subMchId)
                    .nonce_str(WxPayKit.generateStr())
                    .body(orderInfo.getBody())
                    .out_trade_no(orderInfo.getOutOrderNo())
                    .total_fee(String.valueOf(wxTotalTee))
                    .spbill_create_ip(wxJpsoftProperties.getIp())
                    .notify_url(wxJpsoftProperties.getNotifyUrl())
                    .trade_type(TradeType.NATIVE.getTradeType())
                    .build()
                    .createSign(wxJpsoftProperties.getMchKey(), SignType.HMACSHA256);

            String xmlResult = WxPayApi.pushOrder(false, params);
            log.info("统一下单:" + xmlResult);

            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

            String returnCode = result.get("return_code");
            String returnMsg = result.get("return_msg");
            System.out.println(returnMsg);
            if (!WxPayKit.codeIsOk(returnCode)) {
                throw new Exception(returnMsg);
            }
            String resultCode = result.get("result_code");
            if (!WxPayKit.codeIsOk(resultCode)) {
                throw new Exception(returnMsg);
            }
            //生成预付订单success
            String qrCodeUrl = result.get("code_url");


            msgResult.setData(qrCodeUrl);
            msgResult.setResult(true);


        } catch (Exception ex) {

            msgResult.setMessage(ex.getMessage());
            msgResult.setResult(false);
        }
        return msgResult;
    }

}
