package com.cyksj.service.wechat.cache;

import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.service.wechat.WeChatService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 微信缓存 access_token 和 js_ticket
 * 由于每日调用次数有上限 故只能缓存
 *
 * @author valor
 * @date 2019-01-09 18:48
 */
@Component
public class WeChatCache {

    @Autowired
    private WeChatService weChatService;

    /**
     * 缓存access_token 或 js_ticket 的key
     */
    private static final String STRING = "str";

    /**
     * 缓存过期时间的 key
     */
    private static final String TIME = "time";

    private volatile static Map<String, Object> accessTokenMap = null;

    private volatile static Map<String, Object> jsTicketMap = null;

    private WeChatCache() { }

    private volatile static WeChatCache instance = null;

    /**
     * 单例模式 全局有且仅有一个WeChatCache对象
     */
    public static WeChatCache getInstance() {
        if (null == instance) {
            synchronized (WeChatCache.class) {
                if (null == instance) {
                    instance = new WeChatCache();
                }
            }
        }
        return instance;
    }

    /**
     * 获取access_token
     */
    public String getAccessToken() throws Exception {
        if (null == accessTokenMap) {
            synchronized (WeChatCache.class) {
                if (null == accessTokenMap) {
                    accessTokenMap = new HashMap<>(4);
                }
            }
        }

        if (accessTokenMap.containsKey(STRING)) {
            final String str = (String) accessTokenMap.get(STRING);
            if (StringUtils.isBlank(str)) {
                return this.flushAccessToken();
            }

            long now = System.currentTimeMillis();
            if (now > (long) accessTokenMap.get(TIME)) {
                // 过期
                return this.flushAccessToken();
            }
            return str;
        } else {
            // 若服务刚启动 还没有缓存
            return this.flushAccessToken();
        }
    }


    /**
     * 获取js_ticket
     */
    public String getJsTicket() throws Exception {
        if (null == jsTicketMap) {
            synchronized (WeChatCache.class) {
                if (null == jsTicketMap) {
                    jsTicketMap = new HashMap<>(4);
                }
            }
        }

        if (jsTicketMap.containsKey(STRING)) {
            final String str = (String) jsTicketMap.get(STRING);
            if (StringUtils.isBlank(str)) {
                return this.flushJsTicket();
            }

            long now = System.currentTimeMillis();
            if (now > (long) jsTicketMap.get(TIME)) {
                // 过期
                return this.flushJsTicket();
            }
            return str;
        } else {
            // 若服务刚启动 还没有缓存
            return this.flushJsTicket();
        }
    }

    /**
     * 刷新access_token缓存 并返回token
     */
    private String flushAccessToken() throws Exception {
        String token = weChatService.getAccessToken();
        if (StringUtils.isBlank(token)) {
            throw BusinessRuntimeException.getInstance("获取access_token出错.");
        }

        accessTokenMap.put(STRING, token);
        // 设置过期时间 240s 减少向中控服务器请求
        accessTokenMap.put(TIME, System.currentTimeMillis() + 240_000);
        return token;
    }

    /**
     * 刷新js_ticket缓存 并返回ticket
     */
    private String flushJsTicket() throws Exception {
        String ticket = weChatService.getJsTicket();
        if (StringUtils.isBlank(ticket)) {
            throw BusinessRuntimeException.getInstance("获取js_ticket出错.");
        }

        jsTicketMap.put(STRING, ticket);
        // 设置过期时间 240s 减少向中控服务器请求
        jsTicketMap.put(TIME, System.currentTimeMillis() + 240_000);
        return ticket;
    }
}
