package org.jeecg.modules.app.service;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.pay.config.WechatConstants;
import org.jeecg.modules.pay.config.WechatUrlConstants;
import org.jeecg.modules.pay.util.WechatPayV3Utils;
import org.jeecg.modules.system.app.entity.AppOrder;
import org.jeecg.modules.system.app.mapper.AppOrderMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wangzhiqiang
 * @Date 2025/8/21
 * @Desc 微信支付相关服务接口
 */
@Slf4j
@Service
public class WeChatPayService {

    @Resource
    private WechatPayV3Utils wechatPayV3Utils;

    @Resource
    private AppOrderMapper appOrderMapper;


    /**
     * 小程序支付拉起
     *
     * @param params
     * @return
     * @throws ServiceException
     */
    public Map<String, String> wechatPay(JSONObject params) throws ServiceException {

        //发起请求
        JSONObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_JSAPI, params);
        log.info("wechatPay res:{}", res.toString());
        if (res == null || StringUtils.isEmpty(res.getString("prepay_id"))) {
            throw new ServiceException("支付发起失败");
        }

        StringBuilder sb = new StringBuilder();
        //返回给小程序拉起微信支付的参数
        Map<String, String> result = new HashMap<>();
        result.put("appId", WechatConstants.WECHAT_MP_APPID); //小程序appid
        sb.append(result.get("appId")).append("\n");
        result.put("timeStamp", (new Date().getTime() / 1000) + ""); //时间戳
        sb.append(result.get("timeStamp")).append("\n");
        result.put("nonceStr", RandomStringUtils.randomAlphanumeric(32)); //32位随机字符串
        sb.append(result.get("nonceStr")).append("\n");
        result.put("package", "prepay_id=" + res.getString("prepay_id")); //预支付id 格式为 prepay_id=xxx
        sb.append(result.get("package")).append("\n");
        result.put("paySign", wechatPayV3Utils.signRSA(sb.toString())); //签名
        result.put("signType", "RSA"); //加密方式 固定RSA
        result.put("out_trade_no", params.getString("out_trade_no")); //商户订单号 此参数不是小程序拉起支付所需的参数 因此不参与签名

        return result;
    }

//    public static void main(String[] args) {
//        String s = "{\"mchid\":\"1523499681\",\"appid\":\"wx9b0396a7507e3d66\",\"out_trade_no\":\"4022961176\"," +
//                "\"transaction_id\":\"4200001859202306051015832415\",\"trade_type\":\"JSAPI\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"bank_type\":\"ICBC_DEBIT\",\"attach\":\"4022961176\",\"success_time\":\"2023-06-05T14:45:20+08:00\",\"payer\":{\"openid\":\"ok_fR5NmcrTnxFwiSlyd58_TuXrU\"},\"amount\":{\"total\":1,\"payer_total\":1,\"currency\":\"CNY\",\"payer_currency\":\"CNY\"}}";
//        JSONObject res = JSONObject.parseObject(s);
//        String payer_total = res.getJSONObject("amount").getString("payer_total");
//        BigDecimal bigDecimal = new BigDecimal(payer_total);
//        System.out.println(dealDateFormat(res.get("success_time").toString()));
//        //获取当前日期
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
//
//        String format = sdf.format(DateUtils.getNowDate());
//
//        System.out.println(format);
//    }

    public static Date dealDateFormat(String oldDateStr) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        try {
            Date date = df.parse(oldDateStr);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 测试微信支付有优惠情况的数据获取
     *
     * @param args
     */
    public static void main(String[] args) {
        String obj = "{\"amount\":{\"currency\":\"CNY\",\"payer_currency\":\"CNY\",\"payer_total\":18300,\"total\":18400}," +
                "\"appid\":\"wx9b0396a7507e3d66\",\"attach\":\"20230915155102291908100\",\"bank_type\":\"PAB_CREDIT\",\"mchid\":\"1523499681\",\"out_trade_no\":\"20230915155102291908100\",\"payer\":{\"openid\":\"ok_fR5N24KGz9zQBCKNoWgzuT57Y\"},\"promotion_detail\":[{\"amount\":100,\"coupon_id\":\"50099133534\",\"currency\":\"CNY\",\"goods_detail\":[],\"merchant_contribute\":0,\"name\":\"平安信用卡9月专属\",\"other_contribute\":100,\"scope\":\"GLOBAL\",\"stock_id\":\"17950154\",\"type\":\"CASH\",\"wechatpay_contribute\":0}],\"success_time\":\"2023-09-15T15:51:23+08:00\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"JSAPI\",\"transaction_id\":\"4200001916202309158539287225\"}";

        JSONObject res = JSONObject.parseObject(obj);

        String payer_total = res.getJSONObject("amount").getString("payer_total");

        System.out.println(payer_total);

        String openid = res.getJSONObject("payer").getString("openid");

        System.out.println(openid);

        Date successTime = dealDateFormat(res.get("success_time").toString());

        System.out.println(successTime);

        BigDecimal discounts = new BigDecimal("0");

        String discountsName = "";

        if (ObjectUtil.isNotEmpty(res.getJSONArray("promotion_detail"))) {

            JSONArray jsonArray = res.getJSONArray("promotion_detail");

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);

                if (ObjectUtil.isNotEmpty(jsonObject.getString("amount"))) {
                    discounts =
                            discounts.add(new BigDecimal(jsonObject.getString("amount")).divide(new BigDecimal("100")).setScale(2,
                                    BigDecimal.ROUND_HALF_UP));
                }

                if (ObjectUtil.isNotEmpty(jsonObject.getString("name"))) {
                    if ("".equals(discountsName)) {
                        discountsName = jsonObject.getString("name");
                    } else {
                        discountsName = discountsName + "、" + jsonObject.getString("name");
                    }
                }
                System.out.println(res);
            }
        }

        System.out.println(discountsName);
        System.out.println(res.get("promotion_detail").toString());

    }

    /**
     * 小程序微信支付回调
     *
     * @param request
     * @return
     */
    public Map<String, String> wechatPayNotify(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>(2);
        //验签及解析返回数据
        JSONObject res = wechatPayV3Utils.getCallbackData(request);
        if (res == null) {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        log.info("最终拿到的微信支付通知数据：" + res);

        // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意！！！ 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
        try {
            String orderCode = res.getString("out_trade_no");
            //查询订单，判断是否已修改未已支付状态
            AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));

            result.put("code", "SUCCESS");
            result.put("message", "OK");
            result.put("orderCode",orderCode);
            return result;
        } catch (Exception e) {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }

    }

    /**
     * 通过商户订单号查询订单在微信侧支付状态
     *
     * @param out_trade_no 发起支付时创建的商户订单号
     * @return null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
     */
    public String orderQueryByOutTradeNo(String out_trade_no) {
        JSONObject res = wechatPayV3Utils.sendGet(String.format(WechatUrlConstants.PAY_V3_QUERY_OUT, out_trade_no, WechatConstants.WECHAT_MCH_ID));
        return res == null ? null : res.getString("trade_state");
    }

}
