package org.jeecg.modules.transfer;

import com.google.gson.annotations.SerializedName;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.Map;

/**
 * 发起转账
 */
@Slf4j
public class TransferToUser {

    private final String mchid;
    private final String certificateSerialNo;
    private final PrivateKey privateKey;
    private final String wechatPayPublicKeyId;
    private final PublicKey wechatPayPublicKey;

    public TransferToUser(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
        this.mchid = mchid;
        this.certificateSerialNo = certificateSerialNo;
        this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
        this.wechatPayPublicKeyId = wechatPayPublicKeyId;
        this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
    }

//    /**
//     * 微信提现基础参数
//     * @return
//     */
//    public static Map getMap(){
//        Map<String, Object> map = new HashedMap();//转账接口所需参数
//        map.put("host", "https://api.mch.weixin.qq.com");//请求地址
//        map.put("method", "POST");//请求类型
//        map.put("path", "/v3/fund-app/mch-transfer/transfer-bills");//提现接口
//        map.put("notifyUrl", "https://www.yurangongfang.com/massage-admin/massage/cash/cashoutNotify/");//回调接口
//
////        //微信商户参数
////        map.put("appid", "wx77ba4c7131677a74");//小程序appid
////        map.put("mchid", "1712378227");//商户号
////        map.put("certiticateSerialNo", "33E9FE8076531A7C7AD401DC34E053DBD7C28E22");//商户序列号
////        map.put("privateKeyFilePath", "jeecg-boot-module-system/src/main/resources/apiclient_key.pem");//商户私钥证书
////        map.put("wechatPayPublicKeyId", "PUB_KEY_ID_0117123782272025033100396400002931");//商户公钥id
////        map.put("wechatPayPublicKeyFilePath", "jeecg-boot-module-system/src/main/resources/pub_key.pem");//商户公钥证书
////        map.put("transferSceneId", "1005");//商户转账场景ID 1005-佣金报酬
////        map.put("transferRemark", "佣金报酬");//商户转账场景ID 1005-佣金报酬
////        map.put("userRecvPerception", "劳务报酬");//商户转账场景ID 1005-佣金报酬
//
//        //微信商户参数(瑶都万能墙测试参数)
//        map.put("appid", "wxa4d29e67e8a58d38");//小程序appid
//        map.put("mchid", "1673516176");//商户号
//        map.put("certiticateSerialNo", "246ED77A7F882A59FD79993D09FDD2BA9A868FFE");//商户序列号
//        map.put("privateKeyFilePath", "jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem");//商户私钥证书
//        map.put("wechatPayPublicKeyId", "PUB_KEY_ID_0116735161762025040100448900000949");//商户公钥id
//        map.put("wechatPayPublicKeyFilePath", "jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem");//商户公钥证书
//        map.put("transferSceneId", "1005");//商户转账场景ID 1005-佣金报酬
//        map.put("transferRemark", "佣金报酬");//商户转账场景ID 1005-佣金报酬
//        map.put("userRecvPerception", "劳务报酬");//商户转账场景ID 1005-佣金报酬
//
//
//        //变化的用户信息参数
////        map.put("openid", "oFzrW4migndUepy7zYgYO2YoZ5to");//用户openid
////        map.put("userName", "用户真实姓名");//用户真实姓名
//        map.put("transferAmount", 100L);//提现金额, 单位为“分”
//        String idStr = "H" + IdWorker.getIdStr();
//        map.put("outBillNo", idStr);//商户单号
//
//
//        //转账场景报备信息，ransfer_scene_report_infos为数组类型参数，在现金营销的转账场景下需固定传两条明细，每条“转账场景报备信息明细”包含info_type、info_content两个参数。
//        map.put("infoType1","岗位类型");
//        map.put("infoContent1","外卖员");
//        map.put("infoType2","报酬说明");
//        map.put("infoContent2","高温补贴");
//
//        return map;
//
//    }
//
//    public static void main(String[] args) {
//        // TODO: 请准备商户开发必要参数，参考：https://pay.weixin.qq.com/doc/v3/merchant/4013070756
//
//        Map map =  getMap();
//        TransferToUser client = new TransferToUser(
//                map.get("mchid").toString(),  // 商户号，是由微信支付系统生成并分配给每个商户的唯一标识符，商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
//                map.get("certiticateSerialNo").toString(), // 商户API证书序列号，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
//                map.get("privateKeyFilePath").toString(), // 商户API证书私钥文件路径，本地文件路径
//                map.get("wechatPayPublicKeyId").toString(), // 微信支付公钥ID，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
//                map.get("wechatPayPublicKeyFilePath").toString() // 微信支付公钥文件路径，本地文件路径
//        );
//
//        TransferToUserRequest request = new TransferToUserRequest();
//        request.appid = map.get("appid").toString();
//        String idStr = "H" + IdWorker.getIdStr();
//        request.outBillNo = idStr;
//        request.transferSceneId = map.get("transferSceneId").toString();
//        request.openid = map.get("openid").toString();
//        request.userName = client.encrypt(map.get("userName").toString());
//        request.transferAmount = 100L;
//        request.transferRemark = map.get("transferRemark").toString();
//        request.notifyUrl = map.get("notifyUrl").toString();
//        request.userRecvPerception = map.get("userRecvPerception").toString();
//        request.transferSceneReportInfos = new ArrayList<>();
//        {
//            TransferSceneReportInfo item0 = new TransferSceneReportInfo();
//            item0.infoType = map.get("infoType1").toString();
//            item0.infoContent = map.get("infoContent1").toString();
//            request.transferSceneReportInfos.add(item0);
//            TransferSceneReportInfo item1 = new TransferSceneReportInfo();
//            item1.infoType = map.get("infoType2").toString();
//            item1.infoContent = map.get("infoContent2").toString();
//            request.transferSceneReportInfos.add(item1);
//        };
//        try {
//            TransferToUserResponse response = client.run(request, map);
//            // TODO: 请求成功，继续业务逻辑
//            System.out.println(response);
//        } catch (WXPayUtility.ApiException e) {
//            // TODO: 请求失败，根据状态码执行不同的逻辑
//            e.printStackTrace();
//        }
//    }
//
//
//    public TransferToUserResponse run(Map map){
//        TransferToUser client = new TransferToUser(
//                map.get("mchid").toString(),  // 商户号，是由微信支付系统生成并分配给每个商户的唯一标识符，商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
//                map.get("certiticateSerialNo").toString(), // 商户API证书序列号，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
//                map.get("privateKeyFilePath").toString(), // 商户API证书私钥文件路径，本地文件路径
//                map.get("wechatPayPublicKeyId").toString(), // 微信支付公钥ID，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
//                map.get("wechatPayPublicKeyFilePath").toString() // 微信支付公钥文件路径，本地文件路径
//        );
//
//        TransferToUserRequest request = new TransferToUserRequest();
//
//
//        request.appid = map.get("appid").toString();
//        request.outBillNo = map.get("outBillNo").toString();
//        request.transferSceneId = map.get("transferSceneId").toString();
//        request.openid = map.get("openid").toString();
//        request.userName = client.encrypt(map.get("userName").toString());
//        request.transferAmount = 100L;
//        request.transferRemark = map.get("transferRemark").toString();
//        request.notifyUrl = map.get("notifyUrl").toString();
//        request.userRecvPerception = map.get("userRecvPerception").toString();
//        request.transferSceneReportInfos = new ArrayList<>();
//        {
//            TransferSceneReportInfo item0 = new TransferSceneReportInfo();
//            item0.infoType = map.get("infoType1").toString();
//            item0.infoContent = map.get("infoContent1").toString();
//            request.transferSceneReportInfos.add(item0);
//            TransferSceneReportInfo item1 = new TransferSceneReportInfo();
//            item1.infoType = map.get("infoType2").toString();
//            item1.infoContent = map.get("infoContent2").toString();
//            request.transferSceneReportInfos.add(item1);
//        };
//        try {
//            TransferToUserResponse response = client.run(request, map);
//            // TODO: 请求成功，继续业务逻辑
//            log.info("提现发起成功，outBillNo："+response.outBillNo + "，transferBillNo：" +response.transferBillNo + "，state：" +response.state);
//            //转账结果
//            switch (response.state){
//                case ACCEPTED:
//                    log.info("转账已受理");
//                    break;
//                case PROCESSING:
//                    log.info("转账锁定资金中。如果一直停留在该状态，建议检查账户余额是否足够，如余额不足，可充值后再原单重试");
//                    break;
//                case WAIT_USER_CONFIRM:
//                    log.info("待收款用户确认，可拉起微信收款确认页面进行收款确认");
//                    break;
//                case TRANSFERING:
//                    log.info("转账中，可拉起微信收款确认页面再次重试确认收款");
//                    break;
//                case SUCCESS:
//                    log.info("转账成功");
//                    break;
//                case FAIL:
//                    log.info("转账失败");
//                    break;
//                case CANCELING:
//                    log.info("商户撤销请求受理成功，该笔转账正在撤销中");
//                    break;
//                case CANCELLED:
//                    log.info("转账撤销完成");
//                    break;
//            }
//            log.info("提现发起完成");
//            return response;
//        } catch (WXPayUtility.ApiException e) {
//            // TODO: 请求失败，根据状态码执行不同的逻辑
//            log.info("提现发起失败");
//            e.printStackTrace();
//            return null;
//        }
//    }

    public TransferToUserResponse run(TransferToUserRequest request, Map map) {
        String uri = map.get("path").toString();
        String host = map.get("host").toString();
        String method = map.get("method").toString();
        String reqBody = WXPayUtility.toJson(request);

        Request.Builder reqBuilder = new Request.Builder().url(host + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, method, uri, reqBody));
        reqBuilder.addHeader("Content-Type", "application/json");
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
        reqBuilder.method(method, requestBody);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                // 2XX 成功，验证应答签名
                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
                        httpResponse.headers(), respBody);

                // 从HTTP应答报文构建返回数据
                return WXPayUtility.fromJson(respBody, TransferToUserResponse.class);
            } else {
                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
        }
    }

    public String encrypt(String plainText) {
        return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
    }

    public static class TransferToUserResponse {
        @SerializedName("out_bill_no")
        public String outBillNo;

        @SerializedName("transfer_bill_no")
        public String transferBillNo;

        @SerializedName("create_time")
        public String createTime;

        @SerializedName("state")
        public TransferBillStatus state;

        @SerializedName("package_info")
        public String packageInfo;
    }

    public enum TransferBillStatus {
        @SerializedName("ACCEPTED")
        ACCEPTED,
        @SerializedName("PROCESSING")
        PROCESSING,
        @SerializedName("WAIT_USER_CONFIRM")
        WAIT_USER_CONFIRM,
        @SerializedName("TRANSFERING")
        TRANSFERING,
        @SerializedName("SUCCESS")
        SUCCESS,
        @SerializedName("FAIL")
        FAIL,
        @SerializedName("CANCELING")
        CANCELING,
        @SerializedName("CANCELLED")
        CANCELLED
    }

    public static class TransferSceneReportInfo {
        @SerializedName("info_type")
        public String infoType;

        @SerializedName("info_content")
        public String infoContent;
    }

    public static class TransferToUserRequest {
        @SerializedName("appid")
        public String appid;

        @SerializedName("out_bill_no")
        public String outBillNo;

        @SerializedName("transfer_scene_id")
        public String transferSceneId;

        @SerializedName("openid")
        public String openid;

        @SerializedName("user_name")
        public String userName;

        @SerializedName("transfer_amount")
        public Long transferAmount;

        @SerializedName("transfer_remark")
        public String transferRemark;

        @SerializedName("notify_url")
        public String notifyUrl;

        @SerializedName("user_recv_perception")
        public String userRecvPerception;

        @SerializedName("transfer_scene_report_infos")
        public List<TransferSceneReportInfo> transferSceneReportInfos;
    }

}
