package com.cloud.eureka.server.configuration;

import com.cloud.eureka.server.service.MqSendService;
import com.google.common.base.Strings;
import com.netflix.appinfo.InstanceInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.eureka.server.event.*;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * eureka状态改变监听器
 */
@Component
public class EurekaStateChangeListener {
    private static Map<String, List<String>> eventMap = new HashMap<>(30);
    private static Map<String, Long> downMap = new HashMap<>(30);

    private static Boolean isDev = null;

    @Autowired
    private MqSendService mqSendService;

    @Value("${notice.down:null}")
    private String noticeDown;

    @Autowired
    private Environment environment;

    /**
     * 服务下线事件
     *
     * @param event
     */
    @EventListener
    public synchronized void listenDown(EurekaInstanceCanceledEvent event) throws Exception {

        String appName = event.getAppName();
        String serverId = event.getServerId();

        List<String> serverIds = eventMap.getOrDefault(appName, null);

        if (serverIds != null && serverIds.size() > 0 && serverIds.contains(serverId)) {
            serverIds.remove(serverId);
            Long downTime = downMap.getOrDefault(serverId, null);
            Long newTime = System.currentTimeMillis() / 1000;
            if (downTime == null || (newTime - downTime) > 10) {
                sendNotice(appName, serverId, serverIds.size());
                System.out.println(serverId + "\t" + appName + " Service offline");
                downMap.put(serverId, newTime);
            }
        }
    }

    /**
     * 判断并发送通知
     *
     * @param appName
     * @param serverId
     * @param size
     */
    private void sendNotice(String appName, String serverId, int size) {
        if (!Strings.isNullOrEmpty(noticeDown) && !noticeDown.equals("null") && !isDev()) {
            Map<String, Object> entity = new HashMap<>(10);
            entity.put("users", noticeDown);
            entity.put("subject", serverId + "\t" + appName + "服务下线");
            entity.put("content", serverId + "\t" + appName + "服务下线,当前剩余可用数量:" + size);
            mqSendService.send("EMAIL.NEW", entity);
        }
    }

    /**
     * 注册
     *
     * @param event
     */
    @EventListener
    public synchronized void eurekaInstanceRegisteredEvent(EurekaInstanceRegisteredEvent event) {

        InstanceInfo instanceInfo = event.getInstanceInfo();
        String appName = instanceInfo.getAppName();
        String serverId = instanceInfo.getId();
        List<String> serverIds = eventMap.getOrDefault(appName, null);
        if (serverIds == null) {
            serverIds = new ArrayList<>(10);
        }
        if (!serverIds.contains(serverId)) {
            serverIds.add(serverId);
            eventMap.put(appName, serverIds);
            Long downTime = downMap.getOrDefault(serverId, null);
            Long newTime = System.currentTimeMillis() / 1000;
            if (downTime == null || (newTime - downTime) > 10) {
                System.out.println(serverId + "\t" + appName + " Service Online,Current remaining available " +
                        "quantity:" + serverIds.size());
            }

        }
    }

    /**
     * 续约
     *
     * @param event
     */
    @EventListener
    public void eurekaInstanceRenewedEvent(EurekaInstanceRenewedEvent event) {
    }

    /**
     * 注册中心启动
     *
     * @param event
     */
    @EventListener
    public void eurekaRegistryAvailableEvent(EurekaRegistryAvailableEvent event) {
    }

    /**
     * Eureka Server启动时执行
     *
     * @param event
     */
    @EventListener
    public void eurekaServerStartedEvent(EurekaServerStartedEvent event) {

    }

    private boolean isDev() {
        if (isDev == null) {
            if (environment.getActiveProfiles() == null || environment.getActiveProfiles().length <= 0) {
                isDev = false;
            }
            for (String value : environment.getActiveProfiles()) {
                if (!"prod".equals(value)) {
                    isDev = true;
                    return isDev;
                }
            }
        }

        if (isDev == null) {
            isDev = false;
        }

        return isDev;
    }
}