package com.github.niefy.modules.wx.port;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class WxMessageInMemoryDuplicateCheckerSingleton implements WxMessageDuplicateChecker {

    /**
     * 一个消息ID在内存的过期时间：15秒.
     */
    private static final Long TIME_TO_LIVE = 15L;

    /**
     * 每隔多少周期检查消息ID是否过期：5秒.
     */
    private static final Long CLEAR_PERIOD = 5L;

    /**
     * 线程池
     */
    private static final ScheduledThreadPoolExecutor SCHEDULED_THREAD_POOL_EXECUTOR = new ScheduledThreadPoolExecutor(1,
            new ThreadFactoryBuilder().setNameFormat("wxMessage-memory-pool-%d").build(), new ThreadPoolExecutor.AbortPolicy());

    /**
     * 消息id->消息时间戳的map.
     */
    private static final ConcurrentHashMap<String, Long> MSG_ID_2_TIMESTAMP = new ConcurrentHashMap<>();

    static {
        SCHEDULED_THREAD_POOL_EXECUTOR.scheduleAtFixedRate(() -> {
            try {
                Long now = System.currentTimeMillis();
                MSG_ID_2_TIMESTAMP.entrySet().removeIf(entry -> now - entry.getValue() > TIME_TO_LIVE * 1000);
            } catch (Exception ex) {
                log.error("重复消息去重任务出现异常", ex);
            }
        }, 1, CLEAR_PERIOD, TimeUnit.SECONDS);
    }

    /**
     * 私有化构造方法，避免外部调用
     */
    private WxMessageInMemoryDuplicateCheckerSingleton() {
    }

    /**
     * 获取单例
     *
     * @return 单例对象
     */
    public static WxMessageInMemoryDuplicateCheckerSingleton getInstance() {
        return WxMessageInnerClass.CHECKER_SINGLETON;
    }

    /**
     * 内部类实现单例
     */
    private static class WxMessageInnerClass {
        static final WxMessageInMemoryDuplicateCheckerSingleton CHECKER_SINGLETON = new WxMessageInMemoryDuplicateCheckerSingleton();
    }

    /**
     * messageId是否重复
     *
     * @param messageId messageId
     * @return 是否
     */
    @Override
    public boolean isDuplicate(String messageId) {
        if (messageId == null) {
            return false;
        }
        Long timestamp = MSG_ID_2_TIMESTAMP.putIfAbsent(messageId, System.currentTimeMillis());
        return timestamp != null;
    }
}
