package com.ruoyi.api;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.ruoyi.api.util.TransferToUser;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.config.WxAppConfig;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.member.domain.MemberOrder;
import com.ruoyi.member.domain.MemberPoints;
import com.ruoyi.member.service.IMemberOrderService;
import com.ruoyi.member.service.IMemberPointsService;
import com.ruoyi.payConfig.WechatPayConfig;

import com.ruoyi.system.service.ISysUserService;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.RSAPublicKeyConfig;

import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.*;

@RestController
@RequestMapping("/payApi")
public class PayApi {
    @Resource
    private WechatPayConfig wechatPayConfig;

    @Autowired
    private IMemberOrderService memberOrderService;
    @Autowired
    private TransferToUser transferToUser;
    @Autowired
    private IMemberPointsService pointsService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private WxAppConfig appConfig;

    /**
     * type：h5、jsapi、app、native、sub_jsapi

     * @return
     */
    @ApiOperation(value = "统一下单-统一接口", notes = "统一下单-统一接口")
    @GetMapping("/prepayment")
    public PrepayWithRequestPaymentResponse transactions( String orderNo)  {
        LambdaQueryWrapper<MemberOrder> queryWrapper =new LambdaQueryWrapper<>();
        queryWrapper.eq(MemberOrder::getOrderNo,orderNo).last("limit 1");
        MemberOrder memberOrder = memberOrderService.getOne(queryWrapper);
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 使用微信支付公钥的RSA配置
        Config config =
                new RSAPublicKeyConfig.Builder()
                        .merchantId(wechatPayConfig.getMchId())
                        .privateKeyFromPath(wechatPayConfig.getPrivateKeyPath())
                        .publicKeyFromPath(wechatPayConfig.getPublicKeyPath())
                        .publicKeyId(wechatPayConfig.getPublicKeyId())
                        .merchantSerialNumber(wechatPayConfig.getSerialNo())
                        .apiV3Key(wechatPayConfig.getApiV3Key())
                        .build();
        // 构建service
        JsapiServiceExtension service = new JsapiServiceExtension .Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        Payer payer = new Payer();
        BigDecimal goodsPrice = memberOrder.getGoodsPrice();
        // 金额单位为分
        int totalInFen = goodsPrice.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).intValue();
        amount.setTotal(totalInFen);
        payer.setOpenid(user.getWxOpenId());
        request.setAmount(amount);
        request.setAppid(wechatPayConfig.getAppId());
        request.setMchid(wechatPayConfig.getMchId());
        request.setDescription("开通会员");
        request.setNotifyUrl(wechatPayConfig.getNotifyUrl());
        request.setOutTradeNo(orderNo);
        request.setPayer(payer);
        // 调用下单方法，得到应答
        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        return service.prepayWithRequestPayment(request);
    }





    @RequestMapping("/entPay")
    @ApiOperation(value = "商家转账给用户")
    public JSONObject entPay(String orderNo){
        try{
            LambdaQueryWrapper<MemberPoints> queryWrapper =new LambdaQueryWrapper<>();
            queryWrapper.eq(MemberPoints::getOrderNo,orderNo).last("limit 1");
            MemberPoints memberPoints = pointsService.getOne(queryWrapper);
            if (!memberPoints.getUserId().equals(SecurityUtils.getUserId())){
                throw new RuntimeException("非本人账户");
            }
            SysUser sysUser = sysUserService.selectUserById(memberPoints.getUserId());
            // 初始化商户配置
            TransferToUser.TransferToUserRequest userRequest = new TransferToUser.TransferToUserRequest();
            userRequest.appid = appConfig.getAppId();
            userRequest.openid=sysUser.getOpenId();
            // 将元转换为分
            double pointsInYuan = memberPoints.getPoints();
            userRequest.transferAmount = BigDecimal.valueOf(pointsInYuan).multiply(BigDecimal.valueOf(10)).setScale(0, RoundingMode.HALF_UP).longValue();

            userRequest.notifyUrl = wechatPayConfig.getZhuanNotifyUrl();
            userRequest.outBillNo = orderNo;
            userRequest.transferSceneId = "1000";
            userRequest.transferRemark = "通告快接积分提现";
            List<TransferToUser.TransferSceneReportInfo> transferSceneReportInfos  = new ArrayList<>();
            TransferToUser.TransferSceneReportInfo transferSceneReportInfo = new TransferToUser.TransferSceneReportInfo();
            transferSceneReportInfo.infoContent = "发布通告得积分";
            transferSceneReportInfo.infoType = "活动名称";
            TransferToUser.TransferSceneReportInfo transferSceneReportInfo2 = new TransferToUser.TransferSceneReportInfo();
            transferSceneReportInfo2.infoContent = "发布通告得积分";
            transferSceneReportInfo2.infoType = "奖励说明";
            transferSceneReportInfos.add(transferSceneReportInfo);
            transferSceneReportInfos.add(transferSceneReportInfo2);
            userRequest.transferSceneReportInfos = transferSceneReportInfos;
            TransferToUser.TransferToUserResponse run = transferToUser.run(userRequest);
            JSONObject res = new JSONObject();
            res.put("runData",run);
            JSONObject config = new JSONObject();
            config.put("appId",appConfig.getAppId());
            config.put("mchId",wechatPayConfig.getMchId());
            res.put("config",config);
            return res;
        }catch (Exception e){
            LambdaQueryWrapper<MemberPoints> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MemberPoints::getOrderNo,orderNo);
            pointsService.remove(queryWrapper);
            throw new RuntimeException(e);
        }


    }



    @ApiOperation(value = "支付回调", notes = "支付回调")
    @PostMapping("/payNotify")
    @Anonymous
    public Map<String, String> payNotify(@RequestBody JSONObject jsonObject) throws GeneralSecurityException, IOException {
        String key = wechatPayConfig.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();
        //调用业务系统
        memberOrderService.payCallback(orderNo);
        Map<String, String> res = new HashMap<>();
        res.put("code", "SUCCESS");
        res.put("message", "成功");
        return res;
    }


    @ApiOperation(value = "提现支付回调", notes = "提现支付回调")
    @PostMapping("/zhuanNotify")
    @Anonymous
    public Map<String, String> zhuanNotify(@RequestBody JSONObject jsonObject) throws GeneralSecurityException, IOException {
        String key = wechatPayConfig.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_bill_no").toString();
        String state = decryptDataObj.get("state").toString();
        //调用业务系统
        if(state.equals("SUCCESS")){
            pointsService.payoutCallback(orderNo,"success");

            Map<String, String> res = new HashMap<>();
            res.put("code", "SUCCESS");
            res.put("message", "成功");
            return res;
        } else if (state.equals("FAIL")) {
            pointsService.payoutCallback(orderNo,"fail");

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

    }

}
