package com.ruoyi.cms.util;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class WechatUtil {
    /**
     * 生成signature
     **/
    private static String appid = "wx7cab1155e849fe18";
    private static String secret = "0263f34d422d24588d6c2df8f09500ab";
    public AppWechatEntity sign(String url) {
        Map<String, String> ret = new HashMap();
        String nonceStr = create_nonce_str();
        String timestamp = Long.toString(create_timestamp());
        String string1;
        String signature = "";
        //获取jsapi_ticket和过期时间
        AppWechatEntity appWechatEntity = getJsapiTicket();
        String jsapiTicket = appWechatEntity.getJsapi_ticket();
        Long expireTime = appWechatEntity.getExpire_time();
        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapiTicket +
                "&noncestr=" + nonceStr +
                "&timestamp=" + timestamp +
                "&url=" + url;
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes(StandardCharsets.UTF_8));
            signature = byteToHex(crypt.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }

        appWechatEntity.setAppId(appid);
        appWechatEntity.setExpire_time(expireTime);
        appWechatEntity.setNonceStr(nonceStr);
        appWechatEntity.setTimestamp(timestamp);
        appWechatEntity.setSignature(signature);
        return appWechatEntity;
    }


    /**
     * 获取jsapi_ticket
     **/
    public AppWechatEntity getJsapiTicket() {
        //logger.debug("--------------开始执行getJsapiTicket方法--------------");
        //定义过期时间
        AppWechatEntity appWechatEntity = new AppWechatEntity();
        String accessTokenString = "";
        String jsapiTicketString = "";
        String jsapi_ticket = "";
        String access_token = "";
        jsapiTicketString = readWechatTokenFile(getJsapiTicketFilePath());
        if (!StringUtils.isEmpty(jsapiTicketString)) {
            appWechatEntity = JSONObject.parseObject(jsapiTicketString, AppWechatEntity.class);
            long expireTime = appWechatEntity.getExpire_time();
            long curTime = create_timestamp();
            if (expireTime >= curTime && StrUtil.isNotEmpty(appWechatEntity.getJsapi_ticket())) {
                //logger.debug("已有的jsapi_ticket=" + jsapi_ticket);
                return appWechatEntity;
            }
        }

        long timestamp = create_timestamp() + 7000;//过期时间是2小时(7200s)
        access_token =
                getAccessTokenData("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid+ "&secret=" + secret);
        Map accessTokenMap = new HashMap();
        accessTokenMap.put("expire_time", timestamp);
        accessTokenMap.put("access_token", access_token);
        accessTokenString = JSONObject.toJSONString(accessTokenMap);

        jsapi_ticket = getJsapiTicketData("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi");
        Map jsapiTicketMap = new HashMap();
        jsapiTicketMap.put("expire_time", timestamp);
        jsapiTicketMap.put("jsapi_ticket", jsapi_ticket);
        jsapiTicketString = JSONObject.toJSONString(jsapiTicketMap);

        // 写文件
        try {
            FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
            FileUtils.writeStringToFile(new File(getJsapiTicketFilePath()), jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
            //logger.debug("写入文件成功");
        } catch (IOException e) {
            log.debug("写文件异常：" + e.getMessage());
            e.printStackTrace();
        }

        appWechatEntity.setJsapi_ticket(jsapi_ticket);
        appWechatEntity.setExpire_time(timestamp);
        appWechatEntity.setAccess_token(access_token);
        //logger.debug("--------------结束执行getJsapiTicket方法--------------");
        return appWechatEntity;
    }

    public String getAccessToken() {
        //logger.debug("--------------开始执行getAccessToken方法--------------");
        String access_token = "";
        String accessTokenString = "";
        AppWechatEntity appWechatEntity = new AppWechatEntity();
        accessTokenString = readWechatTokenFile(getAccessTokenFilePath());
        if (StringUtils.isNotEmpty(accessTokenString)) {
            appWechatEntity = JSONObject.parseObject(accessTokenString, AppWechatEntity.class);
            access_token = appWechatEntity.getAccess_token();
            long expireTime = appWechatEntity.getExpire_time();
            long curTime = create_timestamp();
            if (expireTime >= curTime) {
                //logger.debug("已有的access_token=" + access_token);
                return access_token;
            }
        }

        long timestamp = create_timestamp() + 6000;//过期时间是2小时，但是可以提前进行更新，防止前端正好过期
        access_token =
                getAccessTokenData("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid  + "&secret=" + secret);
        Map accessTokenMap = new HashMap();
        accessTokenMap.put("expire_time", timestamp);
        accessTokenMap.put("access_token", access_token);
        accessTokenString = JSONObject.toJSONString(accessTokenMap);

        // 写文件
        try {
            FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
        } catch (IOException e) {
            log.debug("写文件异常：" + e.getMessage());
            e.printStackTrace();
        }
        //logger.debug("新的access_token=" + access_token);
        //logger.debug("--------------结束执行getAccessToken方法--------------");
        return access_token;
    }

    private String readWechatTokenFile(String filePath) {
        String content = "";
        try {
            if (new File(filePath).exists()) {
                FileReader fileReader = new FileReader(filePath, CharsetUtil.CHARSET_UTF_8);
                content = fileReader.readString();
            } else {
                new File(filePath).createNewFile();
            }
        } catch (IOException e) {
            log.error("读文件异常：" + e.getMessage());
            e.printStackTrace();
        }
        return content;
    }

    private String getAccessTokenData(String url) {
        String str = "";
        String result = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
        if (StringUtils.isEmpty(result))
            return str;
        str = parseData("access_token", "expires_in", result);
        return str;
    }

    private String getJsapiTicketData(String url) {
        String str = "";
        String result = HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
        if (StringUtils.isEmpty(result))
            return str;
        str = parseData("ticket", "expires_in", result);
        return str;
    }

    private String parseData(String tokenName, String expiresInName, String data) {
        String tokenConent = "";
        JSONObject jsonObject = JSONObject.parseObject(data);
        try {
            tokenConent = jsonObject.get(tokenName).toString();
            if (StringUtils.isEmpty(tokenConent)) {
                log.error("token获取失败,获取结果" + data);
                return tokenConent;
            }
        } catch (Exception e) {
            log.error("token 结果解析失败，token参数名称: " + tokenName + "有效期参数名称:" + expiresInName + "token请求结果:" + data);
            e.printStackTrace();
            return tokenConent;
        }
        return tokenConent;
    }

    private String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private String create_nonce_str() {
        return IdUtil.simpleUUID();
    }

    private Long create_timestamp() {
        return System.currentTimeMillis() / 1000;
    }


    private String getJsapiTicketFilePath() {
        return "/data/wechat" + "/" +appid + "_jsapiTicket.txt";
    }

    private String getAccessTokenFilePath() {
        return "/data/wechat" + "/" + appid + "_accessToken.txt";
    }
}
