package com.ruoyi.cai.controller.app;

import com.alibaba.fastjson2.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfigKit;
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.ruoyi.cai.domain.PayConfig;
import com.ruoyi.cai.pay.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ServletUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/pay")
@Tag(name = "支付相关的接口")
@Validated
@Slf4j
public class PayController {

    @Autowired
    private PayConfigManager payConfigManager;
    @Autowired
    private PayManager payManager;

    @PostMapping(value = "/wx")
    @Operation(summary = "微信支付")
    @Log(title = "微信支付", businessType = BusinessType.OTHER, isSaveDb = true)
    public R<PayReturnResp> appPay(@RequestBody PayControllerDTO dto) {
        PayConfig payConfig = payConfigManager.getWxConfig();
        String ip = ServletUtils.getClientIP();
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(dto.getWxAppId())
                .mch_id(payConfig.getWxMcid())
                .nonce_str(WxPayKit.generateStr())
                .body("微信支付")
                .out_trade_no(WxPayKit.generateStr())
                .total_fee("1000")
                .spbill_create_ip(ip)
                .notify_url(payConfig.getNotifyUrl())
                .trade_type(TradeType.APP.getTradeType())
                .build()
                .createSign(payConfig.getWxKey(), 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");
        if (!WxPayKit.codeIsOk(returnCode)) {
            log.error("微信支付失败 returnMsg={}",returnMsg);
            return R.fail("微信支付失败，请联系客服");
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            log.error("微信支付失败 returnMsg={}",returnMsg);
            return R.fail("微信支付失败，请联系客服");
        }
        // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
        String prepayId = result.get("prepay_id");
        Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(payConfig.getAppid(), payConfig.getWxMcid(), prepayId,
                payConfig.getWxKey(), SignType.HMACSHA256);
        String jsonStr = JSON.toJSONString(packageParams);
        log.info("返回apk的参数:" + jsonStr);
        PayReturnResp resp = new PayReturnResp();
        resp.setData(jsonStr);
        return R.ok(resp);
    }

    @PostMapping(value = "/ali")
    @Operation(summary = "支付宝支付")
    @Log(title = "支付宝支付", businessType = BusinessType.OTHER, isSaveDb = true)
    public R<PayReturnResp> aliPay(@RequestBody PayControllerDTO dto) {
        try {
            boolean b = payConfigManager.initAliPay();
            if(!b){
                return R.fail("支付宝支付失败！请联系管理员");
            }
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody("我是测试数据-By Javen");
            model.setSubject("App支付测试-By Javen");
            model.setOutTradeNo(WxPayKit.generateStr());
            model.setTimeoutExpress("30m");
            model.setTotalAmount("0.01");
            String notifyUrl = AliPayApiConfigKit.getAliPayApiConfig().getServiceUrl();
            String orderInfo = AliPayApi.appPayToResponse(model, notifyUrl).getBody();
            PayReturnResp resp = new PayReturnResp();
            resp.setData(orderInfo);
            return R.ok(resp);
        } catch (AlipayApiException e) {
            log.error("支付宝支付失败",e);
            return R.fail("支付宝支付失败，请联系客服");
        }
    }

    @PostMapping(value = "/wx/notify")
    @Operation(hidden = true)
    @Log(title = "微信回调", businessType = BusinessType.OTHER, isSaveDb = false)
    public String payNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        String returnCode = params.get("return_code");
        String mchId = params.get("mch_id");
        PayConfig payConfig = payConfigManager.getWxConfigByMchId(mchId);
        if(payConfig == null){
            log.error("未找到微信配置 mchId={}",mchId);
            return null;
        }
        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, payConfig.getWxKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                String outTradeNo = params.get("out_trade_no");
                String transactionId = params.get("transaction_id");
//                String appId = params.get("appid");
                payManager.callBack(outTradeNo,transactionId,params,mchId, PayTypeEnum.WX);
                Map<String, String> xml = new HashMap<>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }



    @PostMapping(value = "/ali/notify")
    @Operation(hidden = true)
    @Log(title = "支付宝回调", businessType = BusinessType.OTHER, isSaveDb = false)
    public String notifyUrl(HttpServletRequest request) {
        try {
            Map<String, String> params = AliPayApi.toMap(request);
            log.info("支付宝回调信息:{}",JSON.toJSONString(params));
            String appId = params.get("auth_app_id");
            PayConfig aliConfig = payConfigManager.getAliConfigByAppId(appId);
            boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliConfig.getPublicKey(), "UTF-8", "RSA2");
            if (verifyResult) {
                String outTradeNo = params.get("out_trade_no");
                String transactionId = params.get("trade_no");
                payManager.callBack(outTradeNo,transactionId,params,appId, PayTypeEnum.ALI);
                return "success";
            } else {
                log.error("notify_url 验证失败");
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }
}
