package io.wdd.rpc.scheduler.service.status;

import io.wdd.common.utils.TimeUtils;
import io.wdd.rpc.status.AllAgentStatusCache;
import io.wdd.rpc.status.service.SyncStatusService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

import static io.wdd.rpc.status.AllAgentStatusCache.*;
import static io.wdd.rpc.status.OctopusStatusMessage.ALL_AGENT_STATUS_REDIS_KEY;

/**
 * 定时任务 检测所有的Agent的  存活状态 的实际执行类
 */
@Service
@Slf4j
@Lazy
public class AgentAliveStatusMonitorService {

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    AllAgentStatusCache allAgentStatusCache;

    @Resource
    SyncStatusService syncStatusService;

    private HashMap<String, Boolean> AGENT_HEALTHY_INIT_MAP;

    /**
     * 收集所有Agent的存活状态
     * 实际的定时任务的执行类,
     */
    public void collectAllAgentAliveStatus() {

        // 1. 获取所有注册的Agent 手动更新
        allAgentStatusCache.commonUpdateAllAgentTopicNameCache();
        if (CollectionUtils.isEmpty(ALL_AGENT_TOPIC_NAME_LIST)) {
            log.warn("[Scheduler] No Agent Registered ! End Up Status Monitor !");
            return;
        }

        // 1.1 检查 Agent状态保存数据结构是否正常
        checkOrCreateRedisHealthyKey();

        // 2023年6月14日 2. 发送ping等待所有的Agent返回PONG, 然后进行redis的状态修改
        // 同步的方法, 超时等待所有主机的存活状态
        Map<String, Boolean> agentAliveStatusMap = syncStatusService.SyncCheckAgentIsAlive(
                ALL_AGENT_TOPIC_NAME_LIST,
                5
        );

        // 更新Agent的状态 一级和二级缓存 同时更新 write-through的方式
        updateAllAgentStatusCache(agentAliveStatusMap);

    }

    /**
     * 初始化Agent存活状态的Redis缓存的信息，全部设置为False，然后等待存活状态检测
     */
    private void checkOrCreateRedisHealthyKey() {

        // 检查开始的时候 需要手动将所有Agent的状态置为0
        // Agent如果存活,那么就可以将其自身状态修改为1

        // build the  redis all agent healthy map struct
        HashMap<String, Boolean> initMap = new HashMap<>(32);
        ALL_AGENT_TOPIC_NAME_LIST
                .stream()
                .forEach(
                        agentTopicName -> {
                            initMap.put(
                                    agentTopicName,
                                    Boolean.FALSE
                            );
                        }
                );

        // cache this map struct
        AGENT_HEALTHY_INIT_MAP = initMap;

        // create the healthy redis structure
        redisTemplate
                .opsForHash()
                .putAll(
                        ALL_AGENT_STATUS_REDIS_KEY,
                        initMap
                );

        redisTemplate
                .opsForHash()
                .put(
                        ALL_AGENT_STATUS_REDIS_KEY,
                        STATUS_INIT_TIME_KEY,
                        TimeUtils.currentTimeString()
                );

    }

    public void updateAllAgentStatusCache(Map<String, Boolean> agentAliveStatusMap) {

        String currentTimeString = TimeUtils.currentTimeString();

        // 更新 二级缓存
        allAgentStatusCache.updateAgentStatusCache(agentAliveStatusMap);

        // 更新 一级缓存
        // 这里仅仅是更新时间
        redisTemplate
                .opsForHash()
                .put(
                        ALL_AGENT_STATUS_REDIS_KEY,
                        STATUS_UPDATE_TIME_KEY,
                        currentTimeString
                );

        // 更新所有的Agent状态
        redisTemplate
                .opsForHash()
                .putAll(
                        ALL_AGENT_STATUS_REDIS_KEY,
                        agentAliveStatusMap
                );

        log.debug(
                "[存活状态] - 当前时间为 [ {} ] 一级和二级状态缓存均已经更新",
                currentTimeString
        );

    }


}
