package com.rf.psychological.wxpay.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.rf.psychological.dao.model.CognitiveTaskEntity;
import com.rf.psychological.enums.OrderStatus;
import com.rf.psychological.enums.wxpay.WxApiType;
import com.rf.psychological.enums.wxpay.WxNotifyType;
import com.rf.psychological.enums.wxpay.WxTradeState;
import com.rf.psychological.enums.wxpay.WxTradeType;
import com.rf.psychological.scale.dao.model.SubjectEntity;
import com.rf.psychological.scale.service.CognitiveTaskService;
import com.rf.psychological.scale.service.impl.SubjectServiceImpl;
import com.rf.psychological.utils.RandomUtil;
import com.rf.psychological.utils.Result;
import com.rf.psychological.wxpay.config.WxPayConfig;
import com.rf.psychological.wxpay.model.OrderInfo;
import com.rf.psychological.wxpay.service.OrderInfoService;
import com.rf.psychological.wxpay.service.PaymentInfoService;
import com.rf.psychological.wxpay.service.WxPayService;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
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.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description:微信支付接口
 * @Author: zsf
 * @Date: 2022/6/21
 */
@Service
@Slf4j
@ConditionalOnProperty(prefix="wx.pay",name = "is_lan", havingValue = "false")
public class WxPayServiceImpl implements WxPayService {

    private final ReentrantLock lock =  new ReentrantLock();
    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private CloseableHttpClient wxPayClient;

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private SubjectServiceImpl subjectService;

    @Autowired
    private CognitiveTaskService cognitiveTaskService;

    /**
     * 调用native支付接口
     * @param jsonObject
     * @return code_url和订单号
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> nativePay(JSONObject jsonObject) throws Exception {
        log.info("生成订单");
        Map map = pay(jsonObject,WxTradeType.NATIVE,WxApiType.NATIVE_PAY);
        return map;
    }

    /**
     * 处理订单
     * @param bodyMap 密文数据
     * @throws GeneralSecurityException
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processOrder(Map<String, Object> bodyMap) throws GeneralSecurityException {
        log.info("处理订单");
        //解密报文
        String plainText = decryptFromResource(bodyMap);
        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
        String orderNo = (String)plainTextMap.get("out_trade_no");
        /*在对业务数据进行状态检查和处理之前，
        要采用数据锁进行并发控制，
        以避免函数重入造成的数据混乱*/
        //尝试获取锁：
        // 成功获取则立即返回true，获取失败则立即返回false。不必一直等待锁的释放
        if(lock.tryLock()){
            try {
                //处理重复的通知
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。
                OrderInfo info = orderInfoService.getOrderStatus(orderNo);
                String orderStatus = info !=null?info.getOrderStatus():null;
                if(!OrderStatus.NOTPAY.getType().equals(orderStatus)){
                    return;
                }
                //更新订单状态
                orderInfoService.updateOrderStatus(info, OrderStatus.SUCCESS);
                //记录支付日志
                paymentInfoService.createPaymentInfo(plainText);
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
    }

    /**
     * 取消订单
     * @param orderNo 订单号
     */
    @Override
    public void cancelOrder(String orderNo) throws Exception {
        //调用微信支付的关单接口
        this.closeOrder(orderNo);
        //更新商户端的订单状态
        orderInfoService.cancelOrder(orderNo);
    }

    /**
     * 查询订单
     * @param orderNo
     * @return
     */
    @Override
    public Map queryOrder(String orderNo) throws IOException {
        //拼接url
        String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(),orderNo);
        url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");
        CloseableHttpResponse response = wxPayClient.execute(httpGet);
        try {
            Map resultMap = new HashMap();
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            String body = EntityUtils.toString(response.getEntity());
            resultMap.put("body",body);
            resultMap.put("statusCode",statusCode);
            log.info(orderNo+"-----url------"+body);
            if (statusCode == 200 ||statusCode == 204 ) {
                if (body != null ){
                    Gson gson = new Gson();
                    Map<String, String> resultBody = gson.fromJson(body, HashMap.class);
                    //获取微信支付端的订单状态
                    String tradeState = resultBody.get("trade_state");
                    //判断订单状态
                    if(WxTradeState.SUCCESS.getType().equals(tradeState)){
                        // log.warn("核实订单已支付 ===> {}", orderNo);
                        //如果确认订单已支付则更新本地订单状态
                        orderInfoService.updateOrderStatus(orderNo,OrderStatus.SUCCESS);
                        //记录支付日志
                        paymentInfoService.createPaymentInfo(body);
                    }
                }
               // log.info("成功200");
            }  else {
                log.info("查询失败,响应码 = " + statusCode+"----"+orderNo);
                throw new IOException("request failed");
            }
            return resultMap;
        }finally {
            response.close();
        }
    }

    @Override
    public void checkOrderStatus() throws Exception {
        DateTime nowDate = DateUtil.date();
        //获取未支付订单
        List<OrderInfo> infos = orderInfoService.queryOrderInfoList(OrderStatus.NOTPAY);
        for (OrderInfo info : infos){
            try {
                String orderNo = info.getOrderNo();
                //log.warn("根据订单号核实订单状态 ===> {}", orderNo);
                //调用微信支付查单接口
                Map queryResult = this.queryOrder(orderNo);
                String result = queryResult.get("body").toString();
                Gson gson = new Gson();
                Map<String, String> resultMap = gson.fromJson(result, HashMap.class);
                //获取微信支付端的订单状态
                String tradeState = resultMap.get("trade_state");
                //判断订单状态
                if(WxTradeState.SUCCESS.getType().equals(tradeState)){
                    // log.warn("核实订单已支付 ===> {}", orderNo);
                    //如果确认订单已支付则更新本地订单状态
                    orderInfoService.updateOrderStatus(orderNo,OrderStatus.SUCCESS);
                    //记录支付日志
                    paymentInfoService.createPaymentInfo(result);
                }
                //判断url是否有效 两小时内有效
                String orderType = info.getTradeType();
                long betweenHour = DateUtil.between(nowDate,DateUtil.parseDateTime(info.getUpdateTime()), DateUnit.HOUR);
                long betweenMinute = DateUtil.between(nowDate,DateUtil.parseDateTime(info.getUpdateTime()), DateUnit.MINUTE);
                //log.info(betweenHour+"-------------------"+nowDate+"------------"+info.getUpdateTime());
                if(WxTradeState.NOTPAY.getType().equals(tradeState)
                        &&( (betweenHour >= 2 &&( WxTradeType.NATIVE.getType().equals(orderType)||WxTradeType.JSAPI.getType().equals(orderType)))||(betweenMinute >= 5 && WxTradeType.MWEB.getType().equals(orderType)))){
                    //log.warn("核实订单未支付 ===> {}", orderNo);
                    //如果订单未支付，则调用关单接口
                    this.closeOrder(orderNo);
                    //更新本地订单状态
                    orderInfoService.updateOrderStatus(orderNo, OrderStatus.CLOSED);
                }
                if(WxTradeState.CLOSED.getType().equals(tradeState)){
                    //更新本地订单状态
                    orderInfoService.updateOrderStatus(orderNo, OrderStatus.CLOSED);
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }

    @Override
    public Map<String,Object> h5Pay(JSONObject paramData) throws Exception {
        log.info("h5生成订单");
        //生成订单
        Map<String,Object> map = pay(paramData,WxTradeType.MWEB,WxApiType.H5_PAY);
        return map;
    }

    @Override
    public Map refund(String orderNo) throws IOException {
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType()));
        Gson gson = new Gson();
        Map paramsMap = new HashMap();
        paramsMap.put("out_trade_no","ORDER_20220627180617553");
        paramsMap.put("out_refund_no","REFUND_20220627180617553");
        Map amountMap = new HashMap();
        amountMap.put("refund", 1);
        amountMap.put("total", 1);
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);


        //将body转化为json字符串
        String jsonParams = gson.toJson(paramsMap);
        log.info("请求参数-------"+jsonParams);
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");
        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        String bodyAsString = EntityUtils.toString(response.getEntity());//获取响应体
        int statusCode = response.getStatusLine().getStatusCode();//获取状态码
        if (statusCode == 200){//成功
            log.info("成功，返回结果 = "+bodyAsString);
        }else if (statusCode == 204){//成功 无返回body
            log.info("成功");
        }else {
            log.info("下单失败,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);
            throw new IOException("request failed"+bodyAsString);
        }
        return null;
    }

    @Override
    public Map aspiPay(JSONObject paramObject) throws Exception {
        log.info("aspi预下单订单");
        //生成订单
        Map<String,Object> map = pay(paramObject,WxTradeType.JSAPI,WxApiType.ASPI_PAY);
        return map;
    }




    @Transactional(rollbackFor = Exception.class)
    Map<String, Object> pay(JSONObject paramData, WxTradeType type,WxApiType apiType) throws Exception {
        String productId = paramData.getString("productId");
        String userId = paramData.getString("userId");
        String resultId = paramData.getString("resultId");
        String description = paramData.getString("description");
        String price = paramData.getString("total");
        Integer money = new BigDecimal(String.valueOf(price)).movePointRight(2).intValue();
        OrderInfo orderInfo = orderInfoService.createOrderByProductId(productId,userId,resultId,money,type);
        //判断支付码连接是否存在
        String codeUrl =orderInfo.getCodeUrl();
        log.info("生成订单----------------------"+StringUtils.hasLength(codeUrl));
        if (StringUtils.hasLength(codeUrl) ){
            Map<String,Object> map = new HashMap<>();
            map.put("codeUrl",codeUrl);
            map.put("orderNo",orderInfo.getOrderNo());
            //量表测试次数
            SubjectEntity optional = this.subjectService.getSubjectEntityByFlag(productId);
            if(optional!=null){
                map.put("testNum",optional.getTestNum());
            }else{
                CognitiveTaskEntity optional1 = cognitiveTaskService.getCognizeListByTaskCode(productId);
                if(optional1!=null){
                    map.put("testNum", optional1.getTestNum());
                }else{
                    map.put("testNum","0");
                    log.error("生成支付二维码量表或认知任务已删除：id="+productId);
                }
            }
            return map;
        }
        //调用统一下单API
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(apiType.getType()));
        //构建必要参数
        Gson gson = new Gson();
        Map<String,Object> paramsMap = new HashMap<>();
        if(type.equals(WxTradeType.JSAPI)){
            paramsMap.put("appid",wxPayConfig.getAspi_appid());
        }else{
            paramsMap.put("appid",wxPayConfig.getAppId());
        }
        paramsMap.put("mchid",wxPayConfig.getMchId());
        paramsMap.put("description",description);
        paramsMap.put("out_trade_no",orderInfo.getOrderNo());
        paramsMap.put("notify_url",wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
        Map<String,Object> amountMap = new HashMap<>();
        amountMap.put("total", orderInfo.getTotalFee());
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);
        log.info("paramsMap："+paramsMap);
        if (WxTradeType.MWEB == type){//h5必填参数
            String payerClientIp = paramData.getString("payerClientIp");
            String h5Type = paramData.getString("sceneType");
            HashMap<String,Object> sceneMap = new HashMap<>();
            sceneMap.put("payer_client_ip",payerClientIp);
            Map<String,Object> infoMap = new HashMap<>();
            infoMap.put("type",h5Type);
            sceneMap.put("h5_info",infoMap);
            paramsMap.put("scene_info",sceneMap);
        }else if (WxTradeType.JSAPI == type){//小程序
            Map<String,String> payerMap = new HashMap<>();
            payerMap.put("openid",paramData.getString("openId"));
            paramsMap.put("payer",payerMap);
//            paramsMap.put("nonceStr", RandomUtil.getRandomString(32));
        }
        //将body转化为json字符串
        String jsonParams = gson.toJson(paramsMap);
        log.info("请求参数-------"+jsonParams);
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");
        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        //获取响应
        try {
            String bodyAsString = EntityUtils.toString(response.getEntity());//获取响应体
            int statusCode = response.getStatusLine().getStatusCode();//获取状态码
            if (statusCode == 200){//成功
                log.info("成功，返回结果 = "+bodyAsString);
            }else if (statusCode == 204){//成功 无返回body
                log.info("成功");
            }else {
                log.info("下单失败,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);
                throw new IOException("request failed"+bodyAsString);
            }
            //响应结果
            Map<String,String> resultMap = gson.fromJson(bodyAsString,HashMap.class);
            //获取到二维码连接
            if (WxTradeType.NATIVE == type){
                codeUrl = resultMap.get("code_url");
            }else if (WxTradeType.MWEB==type){
                codeUrl = resultMap.get("h5_url");
            } else if (WxTradeType.JSAPI == type) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("prepay_id",resultMap.get("prepay_id"));
                jsonObject.put("timeStamp",System.currentTimeMillis()/1000+"");
                jsonObject.put("package","prepay_id="+resultMap.get("prepay_id"));
                jsonObject.put("signType","RSA");
                jsonObject.put("appId",wxPayConfig.getAspi_appid());
                jsonObject.put("nonceStr",RandomUtil.getRandomString(32));
                Signature signature = Signature.getInstance("SHA256withRSA");
                signature.initSign(wxPayConfig.getPrivateKey(wxPayConfig.getPrivateKeyPath()));
                StringBuffer buffer = new StringBuffer();
                buffer.append(jsonObject.getString("appId")).append("\n").
                        append(jsonObject.getLong("timeStamp")).append("\n").
                        append(jsonObject.getString("nonceStr")).append("\n").
                        append(jsonObject.getString("package")).append("\n");
                signature.update(buffer.toString().getBytes(StandardCharsets.UTF_8));
                jsonObject.put("paySign",Base64Utils.encodeToString(signature.sign()));
                codeUrl = jsonObject.toJSONString();
            }
            orderInfo.setCodeUrl(codeUrl);
            orderInfoService.saveCodeUrl(orderInfo);
            log.info("orderInfo:" + orderInfo);
            //返回二维码支付链接（小程序返回调起小程序支付参数）
            Map<String, Object> map = new HashMap<>();
            map.put("codeUrl", codeUrl);
            map.put("orderNo", orderInfo.getOrderNo());
            //量表测试次数
            SubjectEntity optional = this.subjectService.getSubjectEntityByFlag(productId);
            if(optional!=null){
                map.put("testNum",optional.getTestNum());
            }else{
                CognitiveTaskEntity optional1 = cognitiveTaskService.getCognizeListByTaskCode(productId);
                if(optional1!=null){
                    map.put("testNum", optional1.getTestNum());
                }else{
                    map.put("testNum","0");
                    log.error("生成支付二维码量表或认知任务已删除：id="+productId);
                }
            }
            return map;
        }finally {
            response.close();
        }
    }


    /**
     * V3  SHA256withRSA 签名.
     *
     * @param method       请求方法  GET  POST PUT DELETE 等
     * @param canonicalUrl 例如  https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1
     * @param timestamp    当前时间戳   因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
     * @param nonceStr     随机字符串  要和TOKEN中的保持一致
     * @param body         请求体 GET 为 "" POST 为JSON
     * @param keyPair      商户API 证书解析的密钥对  实际使用的是其中的私钥
     * @return the string
     */
    @SneakyThrows
    String sign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair)  {
        String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
                .collect(Collectors.joining("\n", "", "\n"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(keyPair.getPrivate());
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64Utils.encodeToString(sign.sign());
    }

    /**
     * 关闭订单
     * @param orderNo
     */
    private void closeOrder(String orderNo) throws Exception {
        log.info("关单接口的调用，订单号 ===> {}", orderNo);

        //创建远程请求对象
        String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
        url = wxPayConfig.getDomain().concat(url);
        HttpPost httpPost = new HttpPost(url);

        //组装json请求体
        Gson gson = new Gson();
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("mchid", wxPayConfig.getMchId());
        String jsonParams = gson.toJson(paramsMap);
        log.info("请求参数 ===> {}", jsonParams);

        //将请求参数设置到请求对象中
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");

        //完成签名并执行请求
        CloseableHttpResponse response = wxPayClient.execute(httpPost);

        try {
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            if (statusCode == 200) { //处理成功
                log.info("成功200");
            } else if (statusCode == 204) { //处理成功，无返回Body
                log.info("成功204");
            } else {
                log.info("取消订单失败,响应码 = " + statusCode);
                throw new IOException("request failed");
            }

        } finally {
            response.close();
        }
    }

    /**
     * 解密数据
     * @param bodyMap
     * @return
     */
    private String decryptFromResource(Map<String, Object> bodyMap) throws GeneralSecurityException {
        log.info("密文解密");

        //通知数据
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        //数据密文
        String ciphertext = resourceMap.get("ciphertext");
        //随机串
        String nonce = resourceMap.get("nonce");
        //附加数据
        String associatedData = resourceMap.get("associated_data");

        log.info("密文 ===> {}", ciphertext);
        AesUtil aesUtil = new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);

        log.info("明文 ===> {}", plainText);

        return plainText;
    }

    /**
     * 获取到token值
     * @return
     * @throws IOException
     */
    @Override
    public String getAccessToken() throws IOException {
        String url = String.format( GET_ACCESS_TOKEN_URL,wxPayConfig.getAspi_appid(),wxPayConfig.getAspi_secret());
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = wxPayClient.execute(httpGet);
        String body = EntityUtils.toString(response.getEntity());
        Gson gson = new Gson();
        HashMap resultBody = gson.fromJson(body, HashMap.class);
        if(resultBody.containsKey("errcode")){
            log.error("获取token异常：");
            log.error("errcode："+resultBody.get("errcode"));
            log.error("errmsg:"+resultBody.get("errmsg"));
        }else{
            return (String) resultBody.get("access_token");
        }
        return null;
    }

    /**
     * 获取到分享链接
     * @param path
     * @return
     */
    @Override
    public String generateLink(String path,String query) throws Exception {
        String linkField = "url_link";
        String url = GENERATE_SHORT_LINK_URL+"?access_token="+this.getAccessToken();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept", "application/json");
        Map<String,Object> map = new HashMap();
        map.put("path",path);
        map.put("query",query);
        StringEntity httpEntity = new StringEntity(JSONObject.toJSONString(map),"utf-8");
        httpPost.setEntity(httpEntity);
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        String body = EntityUtils.toString(response.getEntity());
        JsonObject jsonObject =new Gson().fromJson(body,JsonObject.class);
        if (jsonObject.has(linkField)){
            return jsonObject.get(linkField).getAsString();
        }
        throw new Exception("无link");

    }

    /**
     * 获取小程序码
     * @param page 页面路径
     * @param scene 页面参数
     * @param envVersion 小程序打包版本
     * @return
     */
    @Override
    public String generateWxCode(String page, String scene, String envVersion) {
        try {
            String urlStr = GENERATE_WX_CODE_URL+"?access_token="+getAccessToken();
            HttpPost httpPost = new HttpPost(urlStr);
            httpPost.setHeader("Accept", "application/json");
            Map<String,Object> map = new HashMap();
            map.put("scene", scene);
            map.put("page", page);
            map.put("env_version", envVersion);
            map.put("check_path", false);
            map.put("auto_color", true);
            StringEntity httpEntity = new StringEntity(JSONObject.toJSONString(map),"utf-8");
            httpPost.setEntity(httpEntity);
            CloseableHttpResponse response = wxPayClient.execute(httpPost);
            //开始获取数据
            try (InputStream is = response.getEntity().getContent();
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();) {
                byte[] buffer = new byte[1024];
                int len = -1;
                while ((len = is.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                return Base64.getEncoder().encodeToString(baos.toByteArray());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
