package com.ruoyi.busi.utils;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.config.WxAppConfig;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.payConfig.WechatPayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class WeChatUtils {

    @Resource
    private WechatPayConfig wechatPayConfig;
    @Autowired
    private WxAppConfig wxAppConfig;

    @Autowired
    private RedisCache redisCache;

    // 获取code的接口地址
    public final static String CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    // 获取网页access_token的接口地址
    public final static String WEB_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";

    // 获取用户信息地址
    public final static String USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    // 获取access_token的接口地址（GET） 限2000（次/天）
    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    // 发送模板消息
    public static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    /**
     * 生成获取code的url
     *
     * @param backUrl 回调URL，用户同意授权后重定向的回调链接地址，需要进行URL编码
     * @param state   重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @return 生成的获取code的URL
     */
    public String getCodeUrl(String backUrl, String state) {
        String requestUrl = null;
        state = state == null ? "" : state;
        try {
            requestUrl = CODE_URL.replace("APPID", wechatPayConfig.getAppId())
                    .replace("REDIRECT_URI", URLEncoder.encode(backUrl, "UTF-8"))
                    .replace("STATE", state);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requestUrl;
    }

    /**
     * 获取微信网页access_token 和 openid
     *
     * @param code 用户同意授权后，通过重定向到回调链接中获取的code参数
     * @return 包含access_token和openid的JSONObject
     */
    public JSONObject getWebAccessTokenAndOpenid(String code) {
        String requestUrl = WEB_ACCESS_TOKEN_URL.replace("APPID", wechatPayConfig.getAppId())
                .replace("APPSECRET", wechatPayConfig.getWxAppSecret())
                .replace("CODE", code);
        String response = HttpUtil.get(requestUrl);
        return JSONUtil.parseObj(response);
    }

    /**
     * 网页授权作用域为snsapi_userinfo，则此时开发者可以通过access_token和openid拉取用户信息
     *
     * @param webAccessToken 通过getWebAccessTokenAndOpenid方法获取的access_token
     * @param openid         通过getWebAccessTokenAndOpenid方法获取的openid
     * @return 包含用户信息的JSONObject
     */
    public JSONObject getUserInfo(String webAccessToken, String openid) {
        String requestUrl = USERINFO_URL.replace("ACCESS_TOKEN", webAccessToken)
                .replace("OPENID", openid);
        String response = HttpUtil.get(requestUrl);
        return JSONUtil.parseObj(response);
    }


    /**
     * 获取access_token 先从Redis获取，如果没有再调微信获取并存Redis
     *
     * @return 获取到的access_token
     */
    public String getToken() {
        String accessToken;
        String redisKey = "wechat_access_token";

        // 先从Redis获取
        accessToken = redisCache.getCacheObject(redisKey);
        if (accessToken != null) {
            log.debug("从Redis获取access_token: {}", accessToken);
            return accessToken;
        }

        // 如果Redis中没有或者强制刷新，则从微信获取
        String requestUrl = ACCESS_TOKEN_URL.replace("APPID", wxAppConfig.getAppId())
                .replace("APPSECRET", wxAppConfig.getAppSecret());
        String response = HttpUtil.get(requestUrl);
        JSONObject jsonObject = JSONUtil.parseObj(response);
        accessToken = jsonObject.getStr("access_token");
        int expiresIn = jsonObject.getInt("expires_in", 7200); // 默认有效期为7200秒
        if (accessToken != null) {
            // 将access_token存入Redis，并设置有效期
            redisCache.setCacheObject(redisKey, accessToken,expiresIn - 60,TimeUnit.SECONDS);
            log.debug("从微信获取access_token并存入Redis: {}", accessToken);
        }
        return accessToken;
    }
}
