package com.tiesheng.platform.config.wxmp;


import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
import com.tiesheng.platform.config.wxmp.bean.WxOAuth2AccessToken;
import com.tiesheng.platform.config.wxmp.bean.WxUserInfo;
import com.tiesheng.util.TimedCacheHelper;
import com.tiesheng.util.exception.ApiException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author hao
 */
@Configuration
@ConfigurationProperties(prefix = "platform.wxmp")
public class PlatformWxmpConfig {

    private static final String CACHE_ACCESS_TOKEN = "cache_weixin_access_token_";
    private static final String CACHE_JSAPI_TICKET = "cache_weixin_jsapi_ticket_";


    private WxConfigBean global;
    private Map<String, WxConfigBean> configs = MapUtil.newHashMap();

    /**
     * 获取一个DingConfigBean
     *
     * @param service
     * @return
     */
    public WxConfigBean getConfigBean(String service) {
        WxConfigBean bean = configs.get(service);
        if (bean == null) {
            bean = global;
        }
        if (bean == null) {
            throw new ApiException("该服务未配置微信授权");
        }
        return bean;
    }

    ///////////////////////////////////////////////////////////////////////////
    // 业务逻辑
    ///////////////////////////////////////////////////////////////////////////


    /**
     * 获取accessToken
     *
     * @return
     */
    private String getAccessToken(String service) {
        WxConfigBean configBean = getConfigBean(service);
        String accessToken = TimedCacheHelper.getTimedCache().get(CACHE_ACCESS_TOKEN + configBean.getAppId(), false);
        if (StrUtil.isEmpty(accessToken)) {
            Map<String, Object> query = new HashMap<>(10);
            query.put("grant_type", "client_credential");
            query.put("appid", configBean.getAppId());
            query.put("secret", configBean.getAppSecret());
            String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", query);
            LogFactory.get().info("getAccessToken: " + response);
            JSONObject respJson = JSONUtil.parseObj(response);
            accessToken = respJson.getStr("access_token");
            TimedCacheHelper.getTimedCache().put(CACHE_ACCESS_TOKEN + configBean.getAppId(), accessToken, respJson.getLong("expires_in"));
        }
        return accessToken;
    }


    /**
     * 获取jsapi_ticket
     *
     * @return
     */
    private String getJsapiTicket(String service) {
        WxConfigBean configBean = getConfigBean(service);
        String jsapiTicket = TimedCacheHelper.getTimedCache().get(CACHE_JSAPI_TICKET + configBean.getAppId(), false);
        if (StrUtil.isEmpty(jsapiTicket)) {
            Map<String, Object> query = new HashMap<>(10);
            query.put("access_token", getAccessToken(service));
            query.put("type", "jsapi");
            String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", query);
            LogFactory.get().info("getJsapiTicket: " + response);
            JSONObject respJson = JSONUtil.parseObj(response);
            jsapiTicket = respJson.getStr("ticket");
            TimedCacheHelper.getTimedCache().put(CACHE_JSAPI_TICKET + configBean.getAppId(), jsapiTicket, respJson.getLong("expires_in"));
        }
        return jsapiTicket;
    }


    /**
     * 创建jssdk配置
     *
     * @param url
     * @return
     */
    public WxJsapiSignature createJsapiSignature(String service, String url) {
        WxConfigBean configBean = getConfigBean(service);
        if (StrUtil.contains(url, "#")) {
            url = StrUtil.sub(url, 0, StrUtil.indexOf(url, '#'));
        }
        return WxJsapiSignature.create(configBean.getAppId(), url, getJsapiTicket(service));
    }


    /**
     * 生成认证url
     *
     * @return
     */
    public String buildAuthorizationUrl(String service, String redirectUrl, String scope) {
        WxConfigBean configBean = getConfigBean(service);
        return "https://open.weixin.qq.com/connect/oauth2/authorize"
                + "?appid=" + configBean.getAppId()
                + "&redirect_uri=" + URLUtil.encodeAll(redirectUrl)
                + "&response_type=code&scope=" + scope
                + "&state=STATE#wechat_redirect";
    }


    /**
     * 通过code获取用户授权信息
     *
     * @param code
     * @return
     */
    public WxUserInfo getOAuth2AccessToken(String service, String code) {
        WxConfigBean configBean = getConfigBean(service);
        WxOAuth2AccessToken wxOAuth2AccessToken = WxOAuth2AccessToken.create(configBean.getAppId(), configBean.getAppSecret(), code);
        WxUserInfo wxUserInfo = WxUserInfo.create(wxOAuth2AccessToken);
        wxUserInfo.setAppId(configBean.getAppId());
        return wxUserInfo;
    }


    /**
     * 获取临时素材-图片
     *
     * @return
     * @link <a href='https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.html'></a>
     */
    public void mediaPicGet(String service, String mediaId, String filePath) {
        String fileUrl = String.format("https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s",
                getAccessToken(service), mediaId);
        HttpUtil.downloadFile(fileUrl, filePath);
    }


    ///////////////////////////////////////////////////////////////////////////
    // setter\getter
    ///////////////////////////////////////////////////////////////////////////

    public Map<String, WxConfigBean> getConfigs() {
        return configs;
    }

    public void setConfigs(Map<String, WxConfigBean> configs) {
        this.configs = configs;
    }

    public WxConfigBean getGlobal() {
        return global;
    }

    public void setGlobal(WxConfigBean global) {
        this.global = global;
    }
}
