package com.fastbee.rechargecard.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fastbee.common.utils.pay.AesUtil;
import com.fastbee.common.utils.pay.wxPayConfig;
import com.fastbee.rechargecard.domain.NgMerchants;
import com.fastbee.rechargecard.domain.dto.WeChatRecharge;
import com.fastbee.rechargecard.mapper.NgMerchantsMapper;
import com.fastbee.rechargecard.service.IUserWechatPayService;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;

@Service
public class UserWechatPayServiceImpl implements IUserWechatPayService {

    @Autowired
    private NgMerchantsMapper ngMerchantsMapper;

    /** 商户号 */
    //public static String mchId = "1531795301";
    //public static String mchId = "1503198881";
    /** 商户API私钥文件路径 */
    //public static String privateKeyPath = "fastbee-common/src/main/java/com/fastbee/common/utils/pay/apiclient_key.pem";
    // public static String privateKeyPath = "fastbee-common/src/main/java/com/fastbee/common/utils/pay/damogang_apiclient_key.pem";
    //TODO 生产环境私钥路径
    //public static String privateKeyPath = "/home/soft/hzwmiot/fastbee-admin/target/damogang_apiclient_key.pem";

    /** 商户API证书序列号 */
    //public static String serial_no = "3075B63EF52666EDC3EAFC5D4FB35C02CE123A9C";
   // public static String serial_no = "7A55F5763A002C749F1AB10E1D52DE6688DCDDC0";
    /** 商户APIV3密钥 */
    //public static String apiV3Key = "e85a203e8ca146102f5cd7ecff912580";
   // public static String apiV3Key = "damogangguanqunongcunyunshuizhex";



    //微信支付公钥地址
   // public static String publicKeyPath="fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem";
    //public static String publicKeyPath="fastbee-common/src/main/java/com/fastbee/common/utils/pay/wechat_public_key.pem";
    //平台证书地址
  //  public static String platformCertificatePath="fastbee-common/src/main/java/com/fastbee/common/utils/pay/damogang_platformCertificate.pem";

    //支付结果回调地址
    //  public static String notify_url="https://3ffb1c5f.r3.cpolar.cn/pay/getresult";//https://3ffb1c5f.r3.cpolar.cn
   //TODO 生产环境支付结果异步通知地址
    public static String notify_url="https://farmh5.hze2.com/prod-api/pay/getresult";
    //https://5f655ed0.r3.cpolar.cn
    //微信小程序appid
    public static String appId="wx308612d2a8423311";
    //微信小程序appSecret
    public static String appSecret="7f591f559929a3bf2dbea4e156b08ae9";

    @Override
    /**
     * 创建订单，获取prepay_id和paySign
     * @param recharge
     * @return
     * @throws Exception
     */
    public Map<String, String>  CreateOrder(WeChatRecharge recharge) throws Exception {
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("dept_id",recharge.getDeptId());
        NgMerchants ngMerchants =  ngMerchantsMapper.selectOne(queryWrapper);
        if (ngMerchants==null){
            return null;
        }
        System.out.println("CreateOrder");
        //请求URL
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        Map<String,String> result=new HashMap<>();

        Map<String,Object> reqdata=new HashMap<String,Object>();
        Map<String,Object> amount=new HashMap<>();
        Map<String,Object> payer=new HashMap<>();
        amount.put("total",recharge.getTotal());
        System.out.print(recharge.getTotal());
        amount.put("currency",recharge.getCurrency());
        payer.put("openid",recharge.getOpenId());

        reqdata.put("amount",amount);
        reqdata.put("appid",appId);
//        reqdata.put("mchid",mchId);
        reqdata.put("mchid",ngMerchants.getMchId());
        reqdata.put("description",recharge.getCardnumber()+recharge.getAmount().toString());
        reqdata.put("out_trade_no",recharge.getRechargeCode());
        reqdata.put("notify_url",notify_url);//"\t\n" +
        reqdata.put("payer",payer);
        //String Signature=getSign(reqdata);

        Map<String,String> info=getSign(reqdata,"POST","/v3/pay/transactions/jsapi",ngMerchants.getPrivateKeyPath());
        String timeStamp=info.get("timeStamp");
        String nonce_str=info.get("nonce_str");

        result.put("timeStamp",timeStamp);
//        result.put("mchid",mchId);
        reqdata.put("mchid",ngMerchants.getMchId());
        result.put("signType","RSA");
        result.put("nonceStr",nonce_str);
//        result.put("partnerid",mchId);
        reqdata.put("mchid",ngMerchants.getMchId());
        String Signature=info.get("sign");

        String Authorization="WECHATPAY2-SHA256-RSA2048 mchid=\""+ngMerchants.getMchId()+
                "\",nonce_str=\""+nonce_str+"\",signature=\""+Signature+"\",timestamp=\""+timeStamp+"\",serial_no=\""
                +
//                serial_no
                ngMerchants.getSerialNo()+"\"";

        StringEntity entity = new StringEntity(JSONUtil.toJsonStr(reqdata), "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Authorization",Authorization);

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                // 假设responseEntity是包含JSON响应的字符串
                String responseEntity = EntityUtils.toString(response.getEntity());

                // 使用Hutool的JSONUtil解析JSON字符串
                JSONObject jsonObject = JSONUtil.parseObj(responseEntity);

                // 安全地获取prepay_id的值
                String prepayId = jsonObject.getStr("prepay_id");

                System.out.println("Prepay ID: " + prepayId);
                result.put("prepay_id",prepayId);
                result.put("paySign",getPaySign(prepayId,timeStamp,nonce_str,ngMerchants.getPrivateKeyPath()));
                System.out.println("success,return body = " + prepayId);

                return result;

            } else if (statusCode == 204) {
                return null;
            } else {
                System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } catch (IOException e) {
            response.close();
            httpClient.close();
            throw new RuntimeException(e);
        } finally {
            response.close();
            httpClient.close();
        }
    }


    /**
     * 获取openId
     * @param code
     * @return
     */
    @Override
    public Map<String, Object> GetOpenId(String code)
    {
        System.out.println(code);
        //String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appId, appSecret, code);
        //String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code";
        String url="https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code";
        //RestTemplate restTemplate = new RestTemplate();
        //Map<String, Object> response = restTemplate.getForObject(url, Map.class);

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                String responseString = EntityUtils.toString(response.getEntity());
                Map<String, Object> responseMap = JSONUtil.toBean(responseString, Map.class);
                //打印出返回前端的所有参数
                // 获取键的集合
                Set<String> keySet = responseMap.keySet();
                // 遍历键集合
                for (String key : keySet) {
                    System.out.println(key + ": " + responseMap.get(key));
                }
                // 解析responseString以获取openid
                return responseMap; // 这里返回的是整个响应字符串，需要自行解析出openid
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取平台证书
     * @return
     */
    @Override
    public  Map<String,Object> getPlatformCertificat(String mchId,String privateKey,String serial_no,String apiV3Key)
    {
        String url="https://api.mch.weixin.qq.com/v3/certificates";
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            //生成签名
            Map<String,String> signResult=getSign(null,"GET","/v3/certificates",privateKey);
            Set<String> keySet2 = signResult.keySet();
            // 遍历键集合
            for (String key : keySet2) {
                System.err.println(key + ": " + signResult.get(key));
            }
            String sign=signResult.get("sign").toString();
            String nonce_str=signResult.get("nonce_str").toString();
            String timeStamp=signResult.get("timeStamp").toString();
            String Authorization="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchId+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timeStamp+"\",serial_no=\""+serial_no+"\"";
            System.err.println(Authorization);
            httpGet.setHeader("Accept", "application/json");
            httpGet.setHeader("Authorization",Authorization);

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                String responseString = EntityUtils.toString(response.getEntity());
                System.err.println(responseString);
                Map<String, Object> responseMap = JSONUtil.toBean(responseString, Map.class);
                // 使用Optional来避免null检查
                Optional<?> optionalObj = Optional.ofNullable(responseMap.get("data"));
                System.err.println(optionalObj);
                // 链式调用map和flatMap方法来安全地转换和获取Map
                Map<?, ?> map = optionalObj
                        .filter(List.class::isInstance)  // 确保obj是List类型
                        .map(List.class::cast)          // 将obj转换为List
                        .filter(list -> !list.isEmpty() && list.get(0) instanceof Map) // 确保List不为空，并且第一个元素是Map类型
                        .map(list -> (Map<?, ?>) list.get(0)) // 将List中的第一个元素转换为Map
                        .orElse(null); // 如果任何检查失败，则返回null
                System.err.println(map);
                //解密jsonObject对象
                Map<String,Object> encrypt_certificate= (Map<String, Object>) map.get("encrypt_certificate");
                System.err.println("111");
                System.err.println(encrypt_certificate);
                String serial=map.get("serial_no").toString();
                System.err.println("平台证书序列号："+serial);
                String associated_data=encrypt_certificate.get("associated_data").toString();//加密证书的附加数据，固定为“certificate"
                String ciphertext=encrypt_certificate.get("ciphertext").toString();//加密证书的随机串
                String nonce=encrypt_certificate.get("nonce").toString();//加密后的证书内容
                System.err.println("ciphertext:"+ciphertext);
                System.err.println("nonce:"+nonce);
                System.err.println("associated_data:"+associated_data);
                //使用apiv3key解密
                String decryptData="";
                try{
                    decryptData= new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString
                            (associated_data.getBytes(StandardCharsets.UTF_8),
                                    nonce.getBytes(StandardCharsets.UTF_8),
                                    ciphertext);
                    System.out.println("解密成功：\n"+decryptData);
                }catch (Exception e)
                {
                    System.out.println("解密失败");
                }
                Map<String,Object> result=new HashMap<>();
                result.put("platformCertificate",responseMap.toString());
                result.put("serial",serial);
                Set<String> keys=result.keySet();
                for(String key : keys)
                {
                    System.out.println(key+":"+result.get(key));
                }
                // 解析responseString以获取openid
                return result; // 这里返回的是整个响应字符串，需要自行解析出openid
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成签名
     */
    private Map<String,String> getSign(Map<String,Object> reqBody,String reqMethod,String url,String privateKey) throws Exception {
        //获取时间戳

       /* String reqMethod="POST";
        String url="/v3/pay/transactions/jsapi";*/
        /*String reqMethod="GET";
        String url="/v3/refund/domestic/refunds/123123123123";*/
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        //timeStamp="1554208460";
        String nonce_str= UUID.randomUUID().toString();
        //nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242";
        String reqParam= JSONUtil.toJsonStr(reqBody);
        if(reqBody==null)
        {
            reqParam="";
        }

        /*HTTP请求方法\n
        URL\n
        请求时间戳\n
        请求随机串\n
        请求报文主体\n
        */
        String signStr=reqMethod+"\n"+url+"\n"+timeStamp+"\n"+nonce_str+"\n"+reqParam +"\n";
        System.err.println("signStr:"+signStr);
        //String signStr=reqMethod+"\n"+url+"\n"+timeStamp+"\n"+nonce_str+"\n\n";
        String sign=sign(signStr.getBytes("utf-8"),privateKey);
        Map<String,String> info=new HashMap<>();
        info.put("timeStamp",timeStamp);
        info.put("nonce_str",nonce_str);
        info.put("sign",sign);

        /*//进行sha256
        String sha256HexSignStr = DigestUtil.sha256Hex(signStr);
        //在进行base64
        String base64SignStr = Base64.getEncoder().encodeToString(sha256HexSignStr.getBytes());
*/
        return info;
    }
    /**
     * 生成前端所需签名
     */
    private String getPaySign(String prepayId,String timeStamp,String nonce_str,String privateKey) throws Exception {

        /**
         * 使用字段appId、timeStamp、nonceStr、package
         */
        String signStr=appId+"\n"+timeStamp+"\n"+nonce_str+"\n"+"prepay_id="+prepayId+"\n";
        String sign=sign(signStr.getBytes("utf-8"),privateKey);

        return sign;
    }

    /**
     * 生成签名方法
     * @param message
     * @return
     * @throws Exception
     */
    private String sign(byte[] message,String privateKeyPath) throws Exception{
        Signature sign;
        sign = Signature.getInstance("SHA256withRSA");
        //这里需要一个PrivateKey类型的参数，就是商户的私钥。
        //获取商户私钥——传商户私钥位置

        PrivateKey privateKey = wxPayConfig.getPrivateKey(privateKeyPath);
        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }





}
