package com.ruoyi.hezhi.api.kaoshi;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.weixin.config.WeiXinPayConfig;
import com.ruoyi.common.weixin.utils.WeiXinPayV3NewUtils;
import com.ruoyi.common.weixin.utils.WeiXinPayV3Utils;
import com.ruoyi.hezhi.api.entity.AliPayConfig;
import com.ruoyi.hezhi.api.entity.AlipayService;
import com.ruoyi.hezhi.domain.TbExamRegistration;
import com.ruoyi.hezhi.domain.TbMemberOrder;
import com.ruoyi.hezhi.domain.dto.ExamPayInfoDto;
import com.ruoyi.hezhi.service.ITbExamRegistrationService;
import com.ruoyi.hezhi.service.ITbMemberOrderService;
import com.ruoyi.hezhi.service.IWxPayService;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 支付
 */
@Api("支付")
@RestController
@RequestMapping("/api/pay")
public class ApiPayController {

    private static final Logger log = LoggerFactory.getLogger(ApiPayController.class);
    @Resource
    private ITbMemberOrderService memberOrderService;

    @Resource
    private WeiXinPayV3Utils weiXinPayV3Utils;
    @Resource
    private AliPayConfig aliPayConfig;
    @Resource
    private AlipayService alipayService;
    @Resource
    private WeiXinPayConfig weiXinPayConfig;
    @Resource
    private IWxPayService wxPayService;
    @Resource
    private ITbExamRegistrationService examRegistrationService;
    @Resource
    private WeiXinPayV3NewUtils weiXinPayV3NewUtils;

    /**
     * alipay扫码支付
     */
    @GetMapping("/aliPayScanCode")
    public AjaxResult aliPayScanCode(String orderNo) {
        //todo 检测考试报名时间是否过了（支付宝）【待测试】
        if (StrUtil.isBlank(orderNo)) {
            return AjaxResult.error("参数错误");
        }
        ExamPayInfoDto examPayInfoDto = memberOrderService.selectExamPayInfoByOrderNo(orderNo);
        if (examPayInfoDto != null && examPayInfoDto.getIsExpired() == 1) {
            return AjaxResult.error("考试报名时间已过，请重新报名");
        }
        TbMemberOrder order = memberOrderService.selectOrderByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(order)) {
            return AjaxResult.error("参数错误");
        }
        JSONObject result = new JSONObject();

        BigDecimal payPrice = order.getPayPrice();

        if (payPrice.compareTo(BigDecimal.ZERO) < 1) {
            // 无需支付
            result.put("isNeedPay", 0);
            memberOrderService.orderPayNotify(order.getOrderNo(), 2);
        } else {
            // 需要支付
            result.put("isNeedPay", 1);
            log.info("支付宝预下单，商户订单号：{}", orderNo);
            try {
                TbExamRegistration tbExamRegistration = examRegistrationService.selectTbExamRegistrationByExamRegistrationIdFahuo(order.getDataId());
                if (ObjectUtil.isNull(tbExamRegistration)) {
                    return AjaxResult.error("获取报名信息失败，下单失败");
                }
                String payInfo = alipayService.aliPaySubmit(order.getPayPrice(), order.getOrderNo(), order.getOrderName(), tbExamRegistration.getExamId(), tbExamRegistration.getMemberUserId());
                result.put("payInfo", payInfo);
            } catch (Exception e) {
                e.printStackTrace();
                return AjaxResult.error("下单失败");
            }
        }
        return AjaxResult.success(result);
    }

    /**
     * alipayH5支付
     */
    @GetMapping("/aliPayH5")
    public AjaxResult aliPayH5(String orderNo) {
        //todo 检测考试报名时间是否过了（支付宝）【待测试】
        if (StrUtil.isBlank(orderNo)) {
            return AjaxResult.error("参数错误");
        }
        ExamPayInfoDto examPayInfoDto = memberOrderService.selectExamPayInfoByOrderNo(orderNo);
        if (examPayInfoDto != null && examPayInfoDto.getIsExpired() == 1) {
            return AjaxResult.error("考试报名时间已过，请重新报名");
        }
        TbMemberOrder order = memberOrderService.selectOrderByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(order)) {
            return AjaxResult.error("参数错误");
        }
        JSONObject result = new JSONObject();

        BigDecimal payPrice = order.getPayPrice();

        if (payPrice.compareTo(BigDecimal.ZERO) < 1) {
            // 无需支付
            result.put("isNeedPay", 0);
            memberOrderService.orderPayNotify(order.getOrderNo(), 2);
        } else {
            // 需要支付
            result.put("isNeedPay", 1);
            log.info("支付宝预下单，商户订单号：{}", orderNo);
            try {
                TbExamRegistration tbExamRegistration = examRegistrationService.selectTbExamRegistrationByExamRegistrationIdFahuo(order.getDataId());
                if (ObjectUtil.isNull(tbExamRegistration)) {
                    return AjaxResult.error("获取报名信息失败，下单失败");
                }
                String payInfo = alipayService.aliPayH5Submit(order.getPayPrice(), order.getOrderNo(), order.getOrderName(), tbExamRegistration.getExamId(), tbExamRegistration.getMemberUserId());
                result.put("payInfo", payInfo);
            } catch (Exception e) {
                e.printStackTrace();
                return AjaxResult.error("下单失败");
            }
        }
        return AjaxResult.success(result);
    }

    /***
     * 获取微信支付二维码
     * @param orderNo 订单号
     * @return 结果
     */
    @GetMapping("/createNativePayParam")
    public AjaxResult createNativePayParam(String orderNo) {
        //todo 检测考试报名时间是否过了（微信）【待测试】
        if (StrUtil.isBlank(orderNo)) {
            throw new ServiceException("参数错误");
        }
        ExamPayInfoDto examPayInfoDto = memberOrderService.selectExamPayInfoByOrderNo(orderNo);
        if (examPayInfoDto != null && examPayInfoDto.getIsExpired() == 1) {
            return AjaxResult.error("考试报名时间已过，请重新报名");
        }
        TbMemberOrder order = memberOrderService.selectOrderByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(order)) {
            throw new ServiceException("订单错误");
        }

        BigDecimal payPrice = order.getPayPrice();

        if (payPrice.compareTo(BigDecimal.ZERO) < 1) {
            // 无需支付
            JSONObject data = new JSONObject();
            data.put("isNeedPay", 0);
            memberOrderService.orderPayNotify(orderNo, 1);
            return AjaxResult.success(data);
        } else {
            JSONObject amount = new JSONObject();
            //单位为人民币（分）
            amount.put("total", order.getPayPrice().multiply(new BigDecimal("100")).intValue());
            amount.put("currency", "CNY");

            JSONObject postData = new JSONObject();
            postData.put("appid", weiXinPayConfig.getAppId());
            postData.put("mchid", weiXinPayConfig.getMchId());
            postData.put("description", order.getRemarks());
            postData.put("out_trade_no", orderNo);
            postData.put("notify_url", weiXinPayConfig.getNotifyUrl());
            postData.put("amount", amount);

            log.info("NATIVE下单-参数 => {}", postData.toJSONString());

            // 发送请求
            JSONObject result = weiXinPayV3Utils.sendPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native", postData);
            log.info("NATIVE下单-结果 => {}", postData.toJSONString());
            if (result.containsKey("code_url")) {
                // 支付二维码
                HashMap<String, Object> map = new HashMap<>();
                map.put("codeUrl", result.getString("code_url"));
                map.put("isNeedPay", 1);
                return AjaxResult.success(map);
            } else {
                log.error("NATIVE下单调起失败 <{}> 参数：{}，结果：{}", DateUtils.getTime(), postData.toJSONString(), result.toJSONString());
                throw new ServiceException("NATIVE下单调起失败");
            }
        }
    }



    /***
     * 获取微信支付H5
     * @param orderNo 订单号
     * @return 结果
     */
    @GetMapping("/createH5PayParam")
    public AjaxResult createH5PayParam(String orderNo) {
        if (StrUtil.isBlank(orderNo)) {
            throw new ServiceException("参数错误");
        }
        ExamPayInfoDto examPayInfoDto = memberOrderService.selectExamPayInfoByOrderNo(orderNo);
        if (examPayInfoDto != null && examPayInfoDto.getIsExpired() == 1) {
            return AjaxResult.error("考试报名时间已过，请重新报名");
        }
        TbMemberOrder order = memberOrderService.selectOrderByOrderNo(orderNo);
        if (ObjectUtils.isEmpty(order)) {
            throw new ServiceException("订单错误");
        }

        BigDecimal payPrice = order.getPayPrice();

        if (payPrice.compareTo(BigDecimal.ZERO) < 1) {
            // 无需支付
            JSONObject data = new JSONObject();
            data.put("isNeedPay", 0);
            memberOrderService.orderPayNotify(orderNo, 1);
            return AjaxResult.success(data);
        } else {
            String h5PayUrl = weiXinPayV3NewUtils.createH5PayParam(order.getPayPrice(), orderNo, order.getRemarks());
            log.info("H5下单-结果 => {}", h5PayUrl);
            if (null != h5PayUrl) {
                return AjaxResult.success("操作成功", h5PayUrl);
            } else {
                throw new ServiceException("H5下单调起失败");
            }
        }
    }

    @ResponseBody
    @PostMapping("/createH5PayParamNotify")
    private AjaxResult createH5PayParamNotify(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String code = "FAIL";
        String message = "";
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = weiXinPayV3NewUtils.getNotifyData(httpServletRequest);
            if ("SUCCESS".equals(transaction.getTradeState().name())) {
                log.error("订单回调 <{}> 订单参数 <{}> ", DateUtils.getTime(), transaction);
                // 支付成功
                String orderSn = transaction.getOutTradeNo();
                String msg = "";
                try {
                    msg = memberOrderService.orderPayNotify(orderSn, 1);
                    message = "回调成功";
                } catch (Exception e) {
                    log.error("订单回调 <{}> 订单号 <{}> 订单处理异常", DateUtils.getTime(), orderSn);
                    msg = "FAIL";
                }
                if ("SUCCESS".equals(msg)) {
                    code = "SUCCESS";
                } else {
                    message = "商户业务处理异常";
                }
            } else {
                message = "回调参数异常";
            }
        } catch (Exception e) {
            log.error("订单回调 <{}> 解析异常", DateUtils.getTime());
            message = "回调参数解析异常";
        }
        return AjaxResult.success(message);
    }

    /**
     * 微信支付回调
     *
     * @param httpServletRequest  请求
     * @param httpServletResponse 响应
     */
    @ResponseBody
    @PostMapping("/createNativePayParamNotify")
    public String createNativePayParamNotify(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        log.info("微信支付二维码支付回调 ->" + httpServletRequest);
        String code = "FAIL";
        String message = "";
        try {
            /// 解析回调参数
            JSONObject callbackData = weiXinPayV3Utils.getNotifyDate(httpServletRequest);
            if (ObjectUtil.isNotEmpty(callbackData)) {
                log.info("支付回调参数 ->" + callbackData.toJSONString());
                if (callbackData.containsKey("trade_state") && "SUCCESS".equals(callbackData.get("trade_state"))) {
                    // 支付成功
                    String orderNo = callbackData.getString("out_trade_no");

                    String msg = "";
                    try {
                        msg = memberOrderService.orderPayNotify(orderNo, 1);
                    } catch (Exception e) {
                        e.printStackTrace();
                        msg = "FAIL";
                    }

                    if ("SUCCESS".equals(msg)) {
                        code = "SUCCESS";
                    } else {
                        message = "商户业务处理异常";
                    }

                } else {
                    message = "回调参数异常";
                }
            } else {
                message = "回调参数解析异常";
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("微信支付回调，解析异常");
            message = "回调参数解析异常";
        }
        // 响应报文
        JSONObject returnJson = new JSONObject();
        returnJson.put("code", code);
        returnJson.put("message", message);
        return returnJson.toJSONString();
    }

    /**
     * 支付宝支付回调-学信考试支付
     *
     * @param httpServletRequest  请求
     * @param httpServletResponse 响应
     */
    @PostMapping("/aliPayBoilerNotify")
    @ResponseBody
    public String aliPayBoilerNotify(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        try {
            //获取支付宝POST过来反馈信息
            //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
            Map<String, String> params = new HashMap<String, String>();
            Map requestParams = httpServletRequest.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                params.put(name, valueStr);
            }
            log.error("支付宝支付回调-学信考试支付 <{}> 订单参数 <{}> ", DateUtils.getTime(), params);
            boolean flag = AlipaySignature.rsaCheckV1(params, aliPayConfig.getPublicKey(), "UTF-8", "RSA2");
            if (flag) {
                // 对支付结果中的业务进行验证
                String s = alipayService.checkParams(params);
                if (s.equals("success")) {
                    log.error("支付宝支付回调-学信考试支付 <{}> 签名认证成功 <{}> ", DateUtils.getTime(), params);
                    String orderNo = params.get("out_trade_no");
                    // 业务处理
                    String msg = "";
                    try {
                        msg = memberOrderService.orderPayNotify(orderNo, 2);
                    } catch (Exception e) {
                        log.error("支付宝支付回调-学信考试支付<{}> 订单号 <{}> 订单处理异常", DateUtils.getTime(), orderNo);
                        msg = "FAIL";
                    }
                    if (msg.equals("SUCCESS")) {
                        return "success";
                    } else {
                        return "fail";
                    }
                } else {
                    log.error("支付宝支付回调-学信考试支付 <{}> 签名认证失败 <{}> ", DateUtils.getTime(), params);
                    return "fail";
                }
            } else {
                log.error("支付宝支付回调-学信考试支付 <{}> 解密失败 <{}> ", DateUtils.getTime(), params);
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
    }

    /**
     * 查询订单状态
     *
     * @param orderNo 订单编号
     * @return ok
     */
    @GetMapping("/getOrderStatus")
    public AjaxResult getOrderStatus(String orderNo) {
        try {
            return AjaxResult.success().put("data", memberOrderService.selectOrderByOrderNo(orderNo));
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("查询订单状态异常");
        }
    }

    @GetMapping("/test")
    public AjaxResult test() {

        String s = memberOrderService.orderPayNotify("1870522601479000064", 1);
        return AjaxResult.success();
    }

    /**
     * 创建订单支付
     */
    @GetMapping("/createWxOrder")
    public AjaxResult createWxOrder(@RequestParam String orderNo) {
        return AjaxResult.success(wxPayService.createOrder(orderNo));
    }

}
