package io.wdd.rpc.status;


import io.wdd.common.utils.TimeUtils;
import io.wdd.server.beans.po.ServerInfoPO;
import io.wdd.server.coreService.CoreServerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * Server启动或者运行的时候，需要初 缓存一系列的信息
 * <p>
 * 所有Agent的TopicName   ALL_AGENT_TOPIC_NAME_SET
 * <p>
 * 2023年7月10日 此部分应该初始化全部为 False状态
 * Agent状态信息的两个Map STATUS_AGENT_LIST_MAP ALL_AGENT_STATUS_MAP
 * <p>
 * 2023年7月10日 -- 此部分作为Redis中存储的 二级缓存部分 应该严格遵循
 */
@Service
@Slf4j
public class AllAgentStatusCache {

    /**
     * 存储所有的AgentTopicName的缓存
     */
    public static final Set<String> ALL_AGENT_TOPIC_NAME_SET = new HashSet<>();

    /**
     * 存储所有的AgentTopicName的缓存
     */
    public static final List<String> ALL_AGENT_TOPIC_NAME_LIST = new ArrayList<>();
    /**
     * 存储 状态对应Agent列表的Map
     * Agent的状态描述为 AgentHealthyStatusEnum
     * HEALTHY -> ["agentTopicName-1"， "agentTopicName-2"]
     * FAILED -> ["agentTopicName-1"， "agentTopicName-2"]
     */
    public static final Map<String, List<String>> STATUS_AGENT_LIST_MAP = new HashMap<>();
    /**
     * 存储所有Agent状态的Map
     * <p>
     * 内容为 agentTopicName- True代表健康 False代表不健康
     */
    public static final Map<String, Boolean> ALL_AGENT_STATUS_MAP = new HashMap<>();
    /**
     * 保存所有健康运行的Agent Topic Name
     */
    public static final List<String> ALL_HEALTHY_AGENT_TOPIC_NAME_LIST = new ArrayList<>();
    /**
     * 记录状态信息缓存的更新时间
     */
    public static final String STATUS_UPDATE_TIME_KEY = "A-UPDATE_TIME";
    /**
     * 记录状态信息缓存的初始化时间
     */
    public static final String STATUS_INIT_TIME_KEY = "A-INIT_TIME";
    /**
     * AgentTopicName 在Redis中緩存的Key
     */
    private static final String ALL_AGENT_HEALTHY_MAP_REDIS_KEY = "ALL_AGENT_HEALTHY_MAP";

    private static final String ALL_STATUS_AGENT_MAP_REDIS_KEY = "ALL_STATUS_AGENT_MAP";

    private static final String ALL_AGENT_TOPIC_NAME_SET_REDIS_KEY = "ALL_AGENT_TOPIC_NAME";

    @Resource
    CoreServerService coreServerService;

    @Resource
    JedisPool jedisPool;


    @PostConstruct
    public void InitToGenerateAllStatusCache() {

        //所有Agent的TopicName   ALL_AGENT_TOPIC_NAME_SET
        commonUpdateAllAgentTopicNameCache();
//
        initUpdateAllAgentStatusCache();

        // Agent状态信息的两个Map
        // 初始化 默认创建全部失败的Map
        Map<String, Boolean> initAgentFalseStatusMap = ALL_AGENT_TOPIC_NAME_LIST
                .stream()
                .collect(Collectors.toMap(
                        topicName -> topicName,
                        topicName -> Boolean.FALSE
                ));

        // agent status cache
//        updateAgentStatusCache(initAgentFalseStatusMap);

    }

    private void initUpdateAllAgentStatusCache() {

        if (CollectionUtils.isEmpty(ALL_AGENT_TOPIC_NAME_LIST)) {
            log.info("[Serer Boot Up] - no agent registered yet !");
            return;
        }

        Jedis jedis = jedisPool.getResource();
        // delete from redis
        if (jedis.exists(ALL_AGENT_HEALTHY_MAP_REDIS_KEY)) {
            jedis.del(ALL_AGENT_HEALTHY_MAP_REDIS_KEY);
        }
        if (jedis.exists(ALL_STATUS_AGENT_MAP_REDIS_KEY)) {
            jedis.del(ALL_STATUS_AGENT_MAP_REDIS_KEY);
        }

        // create ALL_AGENT_HEALTHY_MAP_REDIS_KEY
        Map<String, Boolean> initAgentFalseStatusMap = ALL_AGENT_TOPIC_NAME_LIST
                .stream()
                .collect(Collectors.toMap(
                        topicName -> topicName,
                        topicName -> Boolean.FALSE
                ));
        Map<String, String> initAgentFalseRedisMap = ALL_AGENT_TOPIC_NAME_LIST
                .stream()
                .collect(Collectors.toMap(
                        topicName -> topicName,
                        topicName -> Boolean.FALSE.toString()
                ));

        // add time
        String currentFormatTimeString = TimeUtils.currentFormatTimeString();

        initAgentFalseRedisMap.put(STATUS_UPDATE_TIME_KEY, currentFormatTimeString);
        initAgentFalseRedisMap.put(STATUS_INIT_TIME_KEY, currentFormatTimeString);
        if (jedis.hset(ALL_AGENT_HEALTHY_MAP_REDIS_KEY, initAgentFalseRedisMap) > 0) {

            log.debug(" ALL_AGENT_HEALTHY_MAP_REDIS_KEY of {} has updated !", ALL_AGENT_HEALTHY_MAP_REDIS_KEY);
            ALL_AGENT_STATUS_MAP.clear();
            ALL_AGENT_STATUS_MAP.putAll(initAgentFalseStatusMap);
        }

        // create ALL_STATUS_AGENT_MAP_REDIS_KEY
        Map<String, List<String>> statusAgentMapFromAgentStatusMap = buildStatusAgentMapFromAgentStatusMap(initAgentFalseStatusMap);

        // convert
        statusAgentMapFromAgentStatusMap.entrySet().stream().collect(Collectors.toMap(
                entry -> entry.getKey(),
                entry -> String.join(",", entry.getValue())
        ));
        // add time
//        statusAgentMapFromAgentStatusMap.put(STATUS_UPDATE_TIME_KEY, );
//        statusAgentMapFromAgentStatusMap.put(STATUS_UPDATE_TIME_KEY, currentFormatTimeString);


    }

    /**
     * 从数据库中获取所有注册过的Agent名称
     * <p>
     * 2023年7月10日 写入Redis中保存一份
     */
    public void commonUpdateAllAgentTopicNameCache() {

        //查询DB
        List<ServerInfoPO> allAgentInfo = coreServerService.serverGetAll();

        if (CollectionUtils.isEmpty(allAgentInfo)) {
            log.warn("[Serer Boot Up] Octopus Serer First Boot Up ! No Agent Registered Ever!");
            return;
        }

        ALL_AGENT_TOPIC_NAME_LIST.clear();
        ALL_AGENT_TOPIC_NAME_SET.clear();

        List<String> collect = allAgentInfo
                .stream()
                .map(ServerInfoPO::getTopicName)
                .collect(Collectors.toList());

        ALL_AGENT_TOPIC_NAME_LIST.addAll(collect);
        ALL_AGENT_TOPIC_NAME_SET.addAll(collect);

        Jedis jedis = jedisPool.getResource();

        if (jedis.exists(ALL_AGENT_TOPIC_NAME_SET_REDIS_KEY)) {
            jedis.del(ALL_AGENT_TOPIC_NAME_SET_REDIS_KEY);
        }

        String[] all_agent_topic_name_array = new String[ALL_AGENT_TOPIC_NAME_LIST.size()];
        ALL_AGENT_TOPIC_NAME_LIST.toArray(all_agent_topic_name_array);

        jedis.sadd(ALL_AGENT_TOPIC_NAME_SET_REDIS_KEY, all_agent_topic_name_array);
    }


    /**
     *    COMMON-USAGE
     *
     * 根据传入的状态Map更新二级缓存的两个状态Map和健康主机的列表
     * ALL_AGENT_STATUS_MAP
     * STATUS_AGENT_LIST_MAP
     * <p>
     * ALL_HEALTHY_AGENT_TOPIC_NAME_LIST
     */
    public void updateAgentStatusCache(Map<String, Boolean> agentAliveStatusMap) {

        // 检查，排除没有节点的情况
        if (CollectionUtils.isEmpty(ALL_AGENT_TOPIC_NAME_LIST)) {
            log.warn("[Agent Status Cache] No Agent Registered Ever! Return");
            return;
        }

        // 2023年6月15日 更新状态缓存
        ALL_AGENT_STATUS_MAP.clear();
        ALL_AGENT_STATUS_MAP.putAll(agentAliveStatusMap);

        // 2023-01-16
        // 更新 状态-Agent容器 内容为
        //  HEALTHY -> ["agentTopicName-1"， "agentTopicName-2"]
        //  FAILED -> ["agentTopicName-1"， "agentTopicName-2"]
        Map<String, List<String>> statusAgentListMap = agentAliveStatusMap
                .entrySet()
                .stream()
                .collect(
                        Collectors.groupingBy(
                                Map.Entry::getValue
                        )
                )
                .entrySet()
                .stream()
                .collect(
                        Collectors.toMap(
                                entry -> entry.getKey() ? "HEALTHY" : "FAILED",
                                entry -> entry
                                        .getValue()
                                        .stream()
                                        .map(
                                                Map.Entry::getKey
                                        )
                                        .collect(Collectors.toList())
                        )
                );

        // 2023-2-3 bug fix
        STATUS_AGENT_LIST_MAP.clear();
        STATUS_AGENT_LIST_MAP.putAll(statusAgentListMap);

        // 2023年2月21日，更新时间
        String timeString = TimeUtils.currentFormatTimeString();
        STATUS_AGENT_LIST_MAP.put(
                STATUS_UPDATE_TIME_KEY,
                Collections.singletonList(timeString)
        );
        // 2023年12月22日
        ALL_AGENT_STATUS_MAP.put(
                STATUS_UPDATE_TIME_KEY,
                Boolean.TRUE
        );

        // 缓存相应的存活Agent
        List<String> allHealthyAgentTopicNames = agentAliveStatusMap
                .entrySet()
                .stream()
                .filter(
                        entry -> entry
                                .getValue()
                                .equals(Boolean.TRUE)
                )
                .map(
                        Map.Entry::getKey
                )
                .collect(Collectors.toList());

        ALL_HEALTHY_AGENT_TOPIC_NAME_LIST.clear();
        ALL_HEALTHY_AGENT_TOPIC_NAME_LIST.addAll(allHealthyAgentTopicNames);
        log.debug(
                "[状态二级缓存] - ALL_HEALTHY_AGENT_TOPIC_NAME_LIST 为=> {},\n STATUS_AGENT_LIST_MAP 为=> {},\n ALL_AGENT_STATUS_MAP  为=> {}\n",
                ALL_HEALTHY_AGENT_TOPIC_NAME_LIST,
                STATUS_AGENT_LIST_MAP,
                ALL_AGENT_STATUS_MAP
        );


        // 2023年12月22日 add
        Jedis jedis = jedisPool.getResource();

        if (jedis.exists(ALL_AGENT_HEALTHY_MAP_REDIS_KEY)) {
            // get the old cache
            //Map<String, String> all_agent_healthy_map_old = jedis.hgetAll(ALL_AGENT_HEALTHY_MAP_REDIS_KEY);
            // del the old
            jedis.del(ALL_AGENT_HEALTHY_MAP_REDIS_KEY);
        }

        if (jedis.exists(ALL_STATUS_AGENT_MAP_REDIS_KEY)) {
            jedis.del(ALL_STATUS_AGENT_MAP_REDIS_KEY);
        }

        // help gc
        agentAliveStatusMap = null;
        statusAgentListMap = null;
        allHealthyAgentTopicNames = null;
    }

    private Map<String, List<String>> buildStatusAgentMapFromAgentStatusMap(Map<String, Boolean> agentStatusMap) {

        // 2023-01-16 2023年12月22日
        // 更新 状态-Agent容器 内容为
        //  HEALTHY -> ["agentTopicName-1"， "agentTopicName-2"]
        //  FAILED -> ["agentTopicName-1"， "agentTopicName-2"]
        Map<String, List<String>> statusAgentListMap = agentStatusMap
                .entrySet()
                .stream()
                .collect(
                        Collectors.groupingBy(
                                Map.Entry::getValue
                        )
                )
                .entrySet()
                .stream()
                .collect(
                        Collectors.toMap(
                                entry -> entry.getKey() ? "HEALTHY" : "FAILED",
                                entry -> entry
                                        .getValue()
                                        .stream()
                                        .map(
                                                Map.Entry::getKey
                                        )
                                        .collect(Collectors.toList())
                        )
                );

        return statusAgentListMap;
    }

    private String uniformHealthyStatus(String agentStatus) {
        switch (agentStatus) {
            case "0":
                return AgentHealthyStatusEnum.FAILED.getStatus();
            case "1":
                return AgentHealthyStatusEnum.HEALTHY.getStatus();
            default:
                return AgentHealthyStatusEnum.UNKNOWN.getStatus();
        }
    }


}
