package com.heyu.api.data.utils;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.heyu.api.data.dto.AccessTokenDTO;
import com.heyu.api.data.dto.WeiChatLoginDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.HashMap;

@Slf4j
@Component
public class WeChatUtils {


    /**
     * 微信 auth.code2Session 接口
     */
    public final static String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";

    public final static String WECHAT_APPID = "wx75fa59c097bd3dfd";

    public final static String WECHAT_SECRET = "1837c382de696013a2dfc64591e6b854";


    public static final String wechatAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential";


    private static final String linkUrl = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=";

    private static final String schemeUrl = "https://api.weixin.qq.com/wxa/generatescheme?access_token=";


    public static final String wechatQrcodeUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";

    public static final String genwxashortlinkUrl= "https://api.weixin.qq.com/wxa/genwxashortlink?access_token=";


    @Autowired
    private RedisUtils redisUtils;


    @Value("${eb.config.weixin.pay.appid}")
    private String appid;

    @Value("${eb.config.weixin.pay.appSecret}")
    private String appSecret;

    /***
     * 重试次数
     */
    public final static int try_count = 3;

    public final static String access_token_is_invalid = "access_token is invalid";



    public static final String jsapi_acessToken = "jsapi_acessToken";

    public static void main(String[] args) {
        // 获取 openid
        //  WeiChatLoginDTO weiChatLoginDTO = getOpenId("0b1tMGll2jJdBg4sfwml2pnGk32tMGlg",WECHAT_APPID,WECHAT_SECRET);
//        System.out.println(weiChatLoginDTO.getOpenid());
//        System.out.println("o6t1512tT-JuBeT6rIu6RhFGf3BQ".length());
//        System.out.println("FMOMCp63WoRFUJtL4tvjcQ==".length());

    }

    /**
     * 通过微信登录code获取openId
     *
     * @param code 微信登录code
     * @return openId
     */
    // ============json============{"session_key":"FMOMCp63WoRFUJtL4tvjcQ==","openid":"o6t1512tT-JuBeT6rIu6RhFGf3BQ"}
    public WeiChatLoginDTO getOpenId(String code) {
        try {
            // 添加参数
            HashMap<String, String> map = new HashMap<>();
            map.put("appid", appid);
            map.put("secret", appSecret);
            map.put("js_code", code);
            map.put("grant_type", "authorization_code");
            // 使用封装好的HttpClientUtil工具类发送请求
            String result = HttpUtils.doGet(WECHAT_LOGIN_URL, map);
            log.info("getOpenId params:{}, result:{}", JSON.toJSONString(map), result);
            // 将JSON字符串转换为JSONObject对象
            WeiChatLoginDTO weiChatLoginDTO = JSON.parseObject(result, WeiChatLoginDTO.class);
            // 从JSONObject中获取openid并返回
            return weiChatLoginDTO;
        } catch (Exception e) {
            log.error("getOpenId error", e);
        }
        return null;
    }

    public AccessTokenDTO getAccessTokenDTO(boolean useCache) {
        AccessTokenDTO accessTokenDTO = null;
        String acessTokenJson = redisUtils.get(jsapi_acessToken);
        if (StringUtils.isNotEmpty(acessTokenJson) && useCache) {
            log.info("getAccessTokenDTO redis acessToken :{}", acessTokenJson);
            accessTokenDTO = JSONObject.parseObject(acessTokenJson, AccessTokenDTO.class);
        } else {
            String url = String.format(wechatAccessTokenUrl, appid, appSecret);
            String responseBody = HttpUtils.doGet(url);
            log.info("getAccessToken responseBody:{}", responseBody);
            accessTokenDTO = JSONObject.parseObject(responseBody, AccessTokenDTO.class);
            redisUtils.set(jsapi_acessToken, JSON.toJSONString(accessTokenDTO), RedisUtils.one_hours);
        }
        return accessTokenDTO;
    }






    /**
     * 生成小程序跳转短链 code
     * https://blog.csdn.net/weixin_44548582/article/details/131868367
     * <p>
     * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/generateUrlLink.html
     *
     * @param path  小程序页面路径 null为首页
     * @param query 与前端商量，携带的参数
     * @return
     */
    public String jumpAppletShortUrl(String path, String query, Integer days) {
        for (int i = 0; i < try_count; i++) {
            String accessToken = getAccessTokenDTO(true).getAccessToken();
            String url = linkUrl + accessToken;
            cn.hutool.json.JSONObject body = cn.hutool.json.JSONUtil.createObj();
            body.putOpt("path", path);      // 通过 URL Link 进入的小程序页面路径，必须是已经发布的小程序存在的页面，不可携带 query 。path 为空时会跳转小程序主页
            body.putOpt("query", query);    // 通过 URL Link 进入小程序时的query，最大1024个字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~%
            //链接过期类型：0时间戳 1间隔天数
            body.putOpt("expire_type", 1);  // 默认值0.小程序 URL Link 失效类型，失效时间：0，失效间隔天数：1

            //指定失效天数，最多30
            days = (days == null || days > 30) ? 30 : days;
            body.putOpt("expire_interval", days);       // 到期失效的URL Link的失效间隔天数。生成的到期失效URL Link在该间隔时间到达前有效。最长间隔天数为30天。expire_type 为 1 必填

            body.putOpt("env_version", "trial");         // 默认值"release"。要打开的小程序版本。正式版为 "release"，体验版为"trial"，开发版为"develop"，仅在微信外打开时生效。
            String result = HttpUtil.post(url, body.toJSONString(2));
            log.info("jumpAppletShortUrl url:{} params:{}, result:{}", url, JSON.toJSONString(body), result);
            if (StringUtils.isNotEmpty(result) && result.contains(access_token_is_invalid)) {
                getAccessTokenDTO(false);
                continue;
            }
            return result;
        }
        return null;
    }


    /**
     * scheme 跳转微信小程序，需中转H5
     *
     * @param path
     * @param query
     * @param days  https://blog.csdn.net/weixin_44548582/article/details/131868367
     *
     *              https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateScheme.html
     * @return
     */
    public String jumpAppletSchemeUrl(String path, String query, Integer days) {


        for(int i = 0 ; i < try_count ;i ++){
            String url = schemeUrl + getAccessTokenDTO(true).getAccessToken();
            cn.hutool.json.JSONObject body = cn.hutool.json.JSONUtil.createObj();
            cn.hutool.json.JSONObject jumpWxa = cn.hutool.json.JSONUtil.createObj();
            jumpWxa.putOpt("path", path);   // 通过 scheme 码进入的小程序页面路径，必须是已经发布的小程序存在的页面，不可携带 query。path 为空时会跳转小程序主页。
            jumpWxa.putOpt("query", query); // 通过 scheme 码进入小程序时的 query，最大1024个字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~%`
            jumpWxa.putOpt("env_version", "release");       // 默认值"release"。要打开的小程序版本。正式版为"release"，体验版为"trial"，开发版为"develop"，仅在微信外打开时生效。
            body.putOpt("jump_wxa", jumpWxa);           // 跳转到的目标小程序信息。
            //链接过期类型：0时间戳 1间隔天数
            body.putOpt("expire_type", 1);              // 默认值0，到期失效的 scheme 码失效类型，失效时间：0，失效间隔天数：1
            body.putOpt("is_expire", true);
            //指定失效天数，最多30
            days = (days == null || days > 30) ? 30 : days;
            body.putOpt("expire_interval", days);       // 到期失效的 scheme 码的失效间隔天数。生成的到期失效 scheme 码在该间隔时间到达前有效。最长间隔天数为30天。is_expire 为 true 且 expire_type 为 1 时必填
            String post = HttpUtil.post(url, body.toJSONString(2));


            if(StringUtils.isNotEmpty(post) && post.contains(access_token_is_invalid)){
                getAccessTokenDTO(false);
                continue;
            }

            log.info("jumpAppletSchemeUrl url:{} params:{}, result:{}",url, JSON.toJSONString(body), post);
            cn.hutool.json.JSONObject result = cn.hutool.json.JSONUtil.parseObj(post);
            return result.toJSONString(2);

        }


        return null;

    }



    /**
     * scheme 跳转微信小程序，需中转H5
     *
     *https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/short-link/generateShortLink.html
     * @return
     */
    public String genShortlink(String path, String query, Integer days) {
        String resul = null;
        for(int i = 0 ; i < try_count ;i ++){
            String url = genwxashortlinkUrl + getAccessTokenDTO(true).getAccessToken();
            cn.hutool.json.JSONObject body = cn.hutool.json.JSONUtil.createObj();
            body.putOpt("page_url", path);  //通过 Short Link 进入的小程序页面路径，必须是已经发布的小程序存在的页面，可携带 query，最大1024个字符
            body.putOpt("page_title", query);  // 页面标题，不能包含违法信息，超过20字符会用... 截断代替
            body.putOpt("is_permanent", "false");   // 默认值false。生成的 Short Link 类型，短期有效：false，永久有效：true

            String post = HttpUtil.post(url, body.toJSONString(2));
            log.info("genShortlink url:{} params:{}, result:{}",url, JSON.toJSONString(body), url);
            if(StringUtils.isNotEmpty(post) && post.contains(access_token_is_invalid)){
                getAccessTokenDTO(false);
                continue;
            }
            log.info("genShortlink  params:{}, result:{}", JSON.toJSONString(body), post);
            cn.hutool.json.JSONObject result = cn.hutool.json.JSONUtil.parseObj(post);
            return result.toJSONString(2);

        }
        return null;
    }

}
