package com.cubic.agent.core.cmd.jvm.threadpool;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 监控线程池参数
 *
 * @author zhanghao
 * @date 2021/4/59:46 上午
 */
public enum ThreadPoolMonitorItems {
    /**
     * 活动线程数
     */
    ACTIVE_COUNT((t) -> (long) t.getActiveCount()),
    /**
     * 线程数
     */
    POOL_SIZE((t) -> (long) t.getPoolSize()),
    /**
     * 核心线程数
     */
    CORE_POOL_SIZE((t) -> (long) t.getCorePoolSize()),
    /**
     * 存活时间
     */
    KEEP_ALIVE_TIME((t) -> t.getKeepAliveTime(TimeUnit.MILLISECONDS)),
    /**
     * 完成任务数
     */
    COMPLETED_TASK_COUNT((t) -> t.getCompletedTaskCount()),

    /**
     * 最大时的线程数
     */
    LARGEST_POOL_SIZE((t) -> (long) t.getLargestPoolSize()),
    /**
     * 最大线程数
     */
    MAXIMUM_POOL_SIZE((t) -> (long) t.getMaximumPoolSize()),
    /**
     * 计划执行的任务数
     */
    TASK_COUNT((t) -> t.getTaskCount());

    private Function<ThreadPoolExecutor, Long> func;

    ThreadPoolMonitorItems(Function<ThreadPoolExecutor, Long> func) {
        this.func = func;
    }

    /**
     * 采集数据
     *
     * @param tpe 线程池
     * @return
     */
    public static Map<String, Long> getItems(ThreadPoolExecutor tpe) {
        Map<String, Long> items = new HashMap<>();
        for (ThreadPoolMonitorItems items1 : values()) {
            items.put(items1.name(), items1.func.apply(tpe));
        }
        return items;
    }

    /**
     * 线程池唯一键
     * <p>
     * 线程名 + 创建线程栈 + 方法 + hashcode
     *
     * @return
     */
    public static String key(ThreadPoolExecutor executor) {

        String name = "";
        ThreadFactory factory = executor.getThreadFactory();

        Optional<Field> field = Arrays.stream(factory.getClass().getDeclaredFields())
                .filter(e -> e.toString().toLowerCase().contains("prefix")).findAny();
        if (field.isPresent()) {
            field.get().setAccessible(true);
            try {
                name = (String) field.get().get(factory);
            } catch (IllegalAccessException ignored) {
                ;
            }
        }


        if (StringUtils.isNoneBlank(name)) {
            return name;
        }
        name = Thread.currentThread().getName();

        StringBuilder builder = new StringBuilder(name);
        builder.append("-")
                .append(executor.getClass().getName())
                .append("-")
                .append(executor.hashCode());
        return builder.toString();
    }
}
