package cn.iocoder.yudao.module.jx.payment.api;

import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.jx.domain.DriveSchoolCourse;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolCoachMapper;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolCourseMapper;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolInfoMapper;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolReservationCourseMapper;
import cn.iocoder.yudao.module.jx.payment.entity.PayEntity;
import cn.iocoder.yudao.util.WechatPayUrlEnum;
import cn.iocoder.yudao.module.jx.payment.mapper.DrivePayMapper;
import cn.iocoder.yudao.module.jx.payment.utils.AesUtil;
import cn.iocoder.yudao.module.jx.payment.utils.WechatPayRequests;
import cn.iocoder.yudao.module.jx.service.DrivePayService;
import cn.iocoder.yudao.util.WechatPayConfig;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


@Slf4j
@RestController
@RequestMapping("/jxInfo")
public class JxOrderController {

    @Resource
    private DrivePayService drivePayService;
    @Resource
    private WechatPayConfig wechatPayConfigs;
    @Resource
    private WechatPayRequests wechatPayRequests;
    @Resource
    private DrivePayMapper drivePayMapper;
    @Resource
    private DriveSchoolInfoMapper driveSchoolInfoMapper;
    @Resource
    private DriveSchoolCoachMapper driveSchoolCoachMapper;
    @Resource
    private DriveSchoolCourseMapper driveSchoolCourseMapper;
    @Resource
    private DriveSchoolReservationCourseMapper driveSchoolReservationCourseMapper;

    @Resource
    private AdminUserApi userApi;


    @PostMapping("/insertPay")
    public String UserPay(@RequestBody PayEntity PayEntity) {
        if (PayEntity.getStartPay().equalsIgnoreCase("1")) {
            log.info("微信支付================>>>>{}", PayEntity);
            drivePayService.insertPayInfo(PayEntity);
            return PayEntity.getOrderNumber();
        } else {
            System.out.println("线下支付================》》》》");
            return null;
        }
    }

    /**
     * type：h5、jsapi、app、native、sub_jsapi
     * @param type
     * @return
     */
    @GetMapping("/prepayment")
    public Map<String,Object> transactions(String type, Long orderNo,String payType) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = userApi.getUser(userId);
//       SysUser user = SecurityUtils.getLoginUser().getUser();
//        OrderInfo orderInfo = orderInfoService.getById(orderId);
        // 钱， 商品名称
//        PayVo payVoList = drivePayMapper.findPayListByUserId(SecurityFrameworkUtils.getLoginUserId());

        DriveSchoolCourse driveSchoolCourse = driveSchoolCourseMapper.findSchoolCourseByOrderNumber(orderNo);
//        DriveSchoolInfo driveSchoolInfo = driveSchoolInfoMapper.selectDriveSchoolInfoById(Long.valueOf(payVoList.getJxId()));
//        DriveSchoolCoach driveSchoolCoach = driveSchoolCoachMapper.selectDriveSchoolCoachById(Long.valueOf(payVoList.getJlId()));

        // 统一参数封装
        Map<String, Object> params = new HashMap<>(8);
        params.put("appid", wechatPayConfigs.getAppId());
        params.put("mchid", wechatPayConfigs.getMchId());
        params.put("description", driveSchoolCourse.getName());
        params.put("out_trade_no", orderNo.toString());
        params.put("notify_url", wechatPayConfigs.getNotifyUrl());
        Map<String, Object> amountMap = new HashMap<>(4);

        Double amount = 0.0;
        // 金额单位为分
        amount = driveSchoolCourse.getReserveMoney().doubleValue()*100;
        if (payType.equals("2")){
            amount = driveSchoolCourse.getPrice().doubleValue()*100;
        }
        amountMap.put("total", amount.intValue());
        //人民币
        amountMap.put("currency", "CNY");
        params.put("amount", amountMap);

        // 场景信息
        Map<String, Object> sceneInfoMap = new HashMap<>(4);
        // 客户端IP
        sceneInfoMap.put("payer_client_ip", "127.0.0.1");
        // 商户端设备号（门店号或收银设备ID）
        sceneInfoMap.put("device_id", "127.0.0.1");
        // 除H5与JSAPI有特殊参数外，其他的支付方式都一样
        if (type.equals(WechatPayUrlEnum.H5.getType())) {
            Map<String, Object> h5InfoMap = new HashMap<>(4);
            // 场景类型:iOS, Android, Wap
            h5InfoMap.put("type", "IOS");
            sceneInfoMap.put("h5_info", h5InfoMap);
        } else if (type.equals(WechatPayUrlEnum.JSAPI.getType()) || type.equals(WechatPayUrlEnum.SUB_JSAPI.getType())) {
            Map<String, Object> payerMap = new HashMap<>(4);
            //payerMap.put("openid", user.getJcOpenId());
            params.put("payer", payerMap);
        }
        params.put("scene_info", sceneInfoMap);
        String paramsStr = JSON.toJSONString(params);
        log.info("请求参数 ===> {}" + paramsStr);
        String resStr = wechatPayRequests.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",paramsStr);
        Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>(){});
        Map<String, Object> signMap = paySignMsg(resMap.get("prepay_id").toString(), wechatPayConfigs.getAppId(),null);
        return signMap;
    }

    String buildMessage(String appId, String timestamp,String nonceStr,String prepay_id) {

        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepay_id + "\n";
    }

    String sign(byte[] message,String privateKeyStr) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
        //签名方式
        Signature sign = Signature.getInstance("SHA256withRSA");
        //私钥，通过MyPrivateKey来获取，这是个静态类可以接调用方法 ，需要的是_key.pem文件的绝对路径配上文件名
        PrivateKey privateKey =null;
        if (StringUtils.isNotEmpty(privateKeyStr)){
            privateKey = PemUtil.loadPrivateKey(privateKeyStr);
        }else {
            privateKey =  wechatPayConfigs.getPrivateKey(wechatPayConfigs.getKeyPemPath());
        }

        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    private  Map<String, Object>  paySignMsg(String prepayId,String appId,String privateKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        long timeMillis = System.currentTimeMillis();
        String timeStamp = timeMillis/1000+"";
        String nonceStr = timeMillis+"";
        String packageStr = "prepay_id="+prepayId;
        // 公共参数
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("nonceStr",nonceStr);
        resMap.put("timeStamp",timeStamp);
        resMap.put("appId",appId);
        resMap.put("package", packageStr);
        // 使用字段appId、timeStamp、nonceStr、package进行签名
        //从下往上依次生成
        String message = buildMessage(appId, timeStamp, nonceStr, packageStr);
        //签名
        String paySign = sign(message.getBytes("utf-8"), privateKeyStr);
        resMap.put("paySign", paySign);
        resMap.put("signType", "RSA");
        return resMap;
    }


    @PostMapping("/payNotify")
    public Map<String, String> payNotify(@RequestBody JSONObject jsonObject) throws GeneralSecurityException, IOException {
        String key = wechatPayConfigs.getApiV3Key();
        String json = jsonObject.toString();
        String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
        String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
        String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");

        String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        //验签成功
        JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);

        String orderNo = decryptDataObj.get("out_trade_no").toString();

        drivePayMapper.updatePayByOrderNumber(orderNo);

        Map<String, String> res = new HashMap<>();
        res.put("code", "SUCCESS");
        res.put("message", "成功");
        return res;
    }


}
