package com.hc.web.controller.browser.back;

import com.hc.business.dto.ClassCourseDto;
import com.hc.business.dto.UserCourseDto;
import com.hc.business.mapper.*;
import com.hc.business.model.*;
import com.hc.core.utils.pay.browser.wxpay.utils.WxPayBean;
import com.hc.core.utils.properties.PayProperties;
import com.hc.core.utils.result.Result;
import com.hc.core.utils.tool.status.CourseFlagEnum;
import com.hc.core.utils.tool.status.OrdersFlagEnum;
import com.hc.core.utils.wx.XMLUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;

/**
 * @author 10696
 */

@RestController
@RequestMapping("/new/api/back/jsApi")
public class BackWxPayJsApiController {

    private final PayProperties payProperties;

    private final OrdersMapper ordersMapper;

    @Autowired
    private OrderUserLogMapper orderUserLogMapper;

    @Autowired
    private UserCourseMapper userCourseMapper;

    @Autowired
    private ClassCourseMapper classCourseMapper;

    @Autowired
    private UserStatusMapper userStatusMapper;

    @Autowired
    private UserAdviseMapper userAdviseMapper;

    @Autowired
    private ClassConfigMapper classConfigMapper;

    private final String secret = "a58489c01a178deb71a638bc36fdbb56";

    /** 商户API私钥路径 */
    public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
    /** 商户证书序列号 */
    public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
    /** 商户APIV3密钥 */
    public static String apiV3key = "138321670213832167021383216702GP";


    Log log = LogFactory.getLog(this.getClass());

    public BackWxPayJsApiController(PayProperties payProperties, OrdersMapper ordersMapper) {
        this.payProperties = payProperties;
        this.ordersMapper = ordersMapper;
    }


    @PostMapping(value = "/pay", produces = {"application/json;charset=UTF-8"})
    public Result zf1(WxPayBean wxPayBean) {

        Orders ordres = ordersMapper.selectByPrimaryKey(wxPayBean.getOut_trade_no());
        ClassConfig classConfig = classConfigMapper.selectByPrimaryKey(ordres.getClassId());
        String merchantId = payProperties.getWxPay().getMch_id();
        String appId = payProperties.getWxPay().getAppid();
        // 使用自动更新平台证书的RSA配置
        // 建议将 config 作为单例或全局静态对象，避免重复的下载浪费系统资源
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest requestPR = new PrepayRequest();
        Amount amount = new Amount();
        double total_amount = ordres.getTotalAmount() * 100;
        amount.setTotal((int)(total_amount));
        requestPR.setAmount(amount);
        requestPR.setAppid(appId);
        requestPR.setMchid(merchantId);
        requestPR.setDescription(classConfig.getClassName());
        String notifyUrl = "http://jxjy.cfefe.com/new/api/back/jsApi/notify";
        requestPR.setNotifyUrl(notifyUrl);
        requestPR.setOutTradeNo(wxPayBean.getOut_trade_no());
        // 调用下单方法，得到应答
        PrepayResponse responsePR = service.prepay(requestPR);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
        return Result.success(responsePR.getCodeUrl());
    }


    @PostMapping(value = "/notify")
    public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader reader = request.getReader();
        String line = "";
        Map map = new HashMap<>();
        String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";
        StringBuffer inputString = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        request.getReader().close();
        if (inputString.toString().length() > 0) {
            map = XMLUtils.parseXmlToList(inputString.toString());
        } else {
            log.info("接受微信报文为空");
        }
        if (map != null && "SUCCESS".equals(map.get("result_code"))) {
            String out_trade_no = (String) map.get("out_trade_no");
            String transaction_id = (String) map.get("transaction_id");
            Orders orders =
                    ordersMapper.queryByOrderNo(out_trade_no);
            if (Objects.isNull(orders)) {
                return;
            }
            orders.setOrderStatus(OrdersFlagEnum.ORDERS_FLAG_PAID.getCode());
            orders.setTradeNo(transaction_id);
            ordersMapper.updateByPrimaryKey(orders);

            //查询订单中的用户
            Integer ordersId = orders.getOrdersId();
            Integer classId = orders.getClassId();
            List<OrderUserLog> orderUserLogs =
                    orderUserLogMapper.queryByOrderId(ordersId);
            List<ClassCourseDto> classCourseDtoList =
                    classCourseMapper.queryByClassId(classId, CourseFlagEnum.COURSE_REQUIRE_CODE.getCode());

            if (CollectionUtils.isEmpty(orderUserLogs)) {
                if (CollectionUtils.isEmpty(classCourseDtoList)) {
                    return;
                }
                return;
            }

            createUserAdvise(orderUserLogs);
            createUserCourse(classId, orderUserLogs, classCourseDtoList);

            xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } else {
            //失败的业务。。。
        }
        //告诉微信端已经确认支付成功
        response.getWriter().write(xml);
    }

    /**
     * 生成 MD5
     *
     * @param data 待处理数据
     * @return MD5结果
     */
    private static String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 生成随机数
     * <p>算法参考：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3</p>
     *
     * @return 随机数字符串
     */

    private static String createNonceStr() {
        SecureRandom random = new SecureRandom();
        int randomNum = random.nextInt();
        return Integer.toString(randomNum);
    }

    /**
     * 生成签名，用于在微信支付前，获取预支付时候需要使用的参数sign
     * <p>算法参考：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3</p>
     *
     * @param params 需要发送的所有数据设置为的Map
     * @return 签名sign
     */

    private String createSign(TreeMap<String, String> params) {
        String signValue = "";
        String stringSignTemp = "";

        String stringA = "";
        //获得stringA
        Set<String> keys = params.keySet();
        for (String key : keys) {
            stringA += (key + "=" + params.get(key) + "&");
        }
        stringA = stringA.substring(0, stringA.length() - 1);
        //获得stringSignTemp
        stringSignTemp = stringA + "&key=" + payProperties.getWxPay().getSign_key();
        //获得signValue
        signValue = encryptByMD5(stringSignTemp).toUpperCase();
        return signValue;
    }

    /**
     * MD5加密
     *
     * @param sourceStr
     * @return
     */

    private static String encryptByMD5(String sourceStr) {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(sourceStr.getBytes(StandardCharsets.UTF_8));
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            result = buf.toString();
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e);
        }
        return result;
    }

    private void createUserAdvise(List<OrderUserLog> orderUserLogs) {
        orderUserLogs.forEach(orderUserLog -> {
            UserAdvise userAdvise = new UserAdvise();
            userAdvise.setAdviceType(1);
            userAdvise.setCreateTime(System.currentTimeMillis());
            userAdvise.setAdvise("报名成功,这里是一行通知。。。。。");
            userAdvise.setUserId(orderUserLog.getReUserId());
            userAdvise.setTitle("标题");
            userAdviseMapper.insert(userAdvise);
        });
    }

    private void createUserCourse(Integer classId,
                                  List<OrderUserLog> orderUserLogs,
                                  List<ClassCourseDto> classCourseDtoList) {

        orderUserLogs.forEach(orderUserLog -> {
            Integer reUserId = orderUserLog.getReUserId();
            Integer ordersId = orderUserLog.getOrderId();
            Integer statusId=0;
            //开用户状态
            List<UserStatus> userStatuses =
                    userStatusMapper.queryByClassIdAndUserId(classId, reUserId);
            if (CollectionUtils.isEmpty(userStatuses)) {
                UserStatus userStatus = new UserStatus();
                userStatus.setClassId(classId);
                userStatus.setOrderId(ordersId);
                userStatus.setUserId(reUserId);
                userStatus.setStatus(OrdersFlagEnum.ORDERS_FLAG_PAID.getCode());
                userStatusMapper.insert(userStatus);

                statusId =userStatus.getStatusId();

            }else {
                statusId = userStatuses.get(0).getStatusId();

            }
            //课程
            Integer finalStatusId = statusId;
            classCourseDtoList.forEach(classCourseDto -> {
                Integer courseId = classCourseDto.getCourseId();
                //是否已开
                List<UserCourseDto> userCourses
                        = userCourseMapper.selectUserCourseProgress(reUserId, classId, courseId);
                if (CollectionUtils.isEmpty(userCourses)) {
                    //开课
                    UserCourse userCourse = new UserCourse();
                    userCourse.setClassId(classId);
                    userCourse.setCourseId(courseId);
                    userCourse.setUserId(reUserId);
                    userCourse.setCoursePercent(0.00);
                    userCourse.setStatusId(finalStatusId);
                    userCourseMapper.insert(userCourse);
                }
            });
        });
    }


}
