package com.sohu.cache.inspect.impl;

import com.sohu.cache.alert.impl.BaseAlertService;
import com.sohu.cache.entity.AppDesc;
import com.sohu.cache.entity.InstanceInfo;
import com.sohu.cache.entity.InstanceStats;
import com.sohu.cache.inspect.InspectParamEnum;
import com.sohu.cache.inspect.Inspector;
import com.sohu.cache.stats.app.AppStatsCenter;
import com.sohu.cache.stats.instance.InstanceStatsCenter;
import com.sohu.cache.util.ConstUtils;
import com.sohu.cache.util.TypeUtil;
import com.sohu.cache.web.enums.AlertTypeEnum;
import com.sohu.cache.web.vo.AppDetailVO;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 应用客户端连接监控
 * 
 * @author leifu
 * @Date 2016年6月16日
 * @Time 上午9:44:34
 */
public class AppClientConnInspector extends BaseAlertService implements Inspector {

    /**
     * app统计相关
     */
    private AppStatsCenter appStatsCenter;

    /**
     * 实例统计相关
     */
    private InstanceStatsCenter instanceStatsCenter;

    @Override
    public boolean inspect(Map<InspectParamEnum, Object> paramMap) {
        Long appId = MapUtils.getLong(paramMap, InspectParamEnum.SPLIT_KEY);
        AppDetailVO appDetailVO = appStatsCenter.getAppDetail(appId);
        if (appDetailVO == null) {
            logger.warn("appId {} appDetailVO is empty", appId);
            return true;
        }
        List<InstanceInfo> appInstanceInfoList = (List<InstanceInfo>) paramMap.get(InspectParamEnum.INSTANCE_LIST);
        if (CollectionUtils.isEmpty(appInstanceInfoList)) {
            logger.warn("appId {} instanceList is empty", appId);
            return true;
        }
        // 报警阀值
        int appClientConnThreshold = getClientConnThreshold(appDetailVO.getAppDesc());
        int appClientConnNum = appDetailVO.getConn();
        // 阀值乘以分片个数
        int instanceCount = appInstanceInfoList.size();
        if (appClientConnNum > appClientConnThreshold * instanceCount) {
            alertAppClientConn(appDetailVO, appClientConnThreshold, instanceCount);
        } else {
            for (InstanceInfo instanceInfo : appInstanceInfoList) {
                if (instanceInfo == null) {
                    continue;
                }
                if (instanceInfo.isOffline()) {
                    continue;
                }
                if (!TypeUtil.isRedisType(instanceInfo.getType())) {
                    continue;
                }
                // 忽略sentinel观察者
                if (TypeUtil.isRedisSentinel(instanceInfo.getType())) {
                    continue;
                }
                long instanceId = instanceInfo.getId();
                InstanceStats instanceStats = instanceStatsCenter.getInstanceStats(instanceId);
                if (instanceStats == null) {
                    continue;
                }
                double instanceClientConnNum = instanceStats.getCurrConnections();
                // 大于标准值
                if (instanceClientConnNum > appClientConnThreshold) {
                    alertInstanceClientConn(instanceStats, appDetailVO, appClientConnThreshold);
                }
            }
        }
        return true;
    }

    /**
     * 获取报警阀值(如果用户预设超过系统预设，以系统为准，反之以用户为准)
     * @param appDesc
     * @return
     */
    private int getClientConnThreshold(AppDesc appDesc) {
        int userClientConnThreshold = appDesc.getClientConnAlertValue();
        int systemClientConnThreshold =  ConstUtils.APP_CLIENT_CONN_THRESHOLD;
        return userClientConnThreshold > systemClientConnThreshold ? systemClientConnThreshold : userClientConnThreshold;
    }

    /**
     * 应用连接数报警
     * @param appDetailVO
     * @param appClientConnThreshold
     * @param instanceCount
     */
    private void alertAppClientConn(final AppDetailVO appDetailVO, final int appClientConnThreshold, final int instanceCount) {
        AppDesc appDesc = appDetailVO.getAppDesc();
        String content = String.format("应用(%s)-客户端连接数报警-预设阀值每个分片为%s-现已达到%s(分片个数:%s)-请及时关注",
                appDesc.getAppId(), appClientConnThreshold, appDetailVO.getConn(), instanceCount);
        String title = "CacheCloud系统-客户端连接数报警";
        logger.warn("app title {}", title);
        logger.warn("app content {}", content);
        appAlertRecordService.saveAlertInfoByType(AlertTypeEnum.APP_CLIENT_CONNECTION, title, content, appDetailVO);
        emailComponent.sendMail(title, content, appDetailVO.getEmailList(),
                Arrays.asList(emailComponent.getAdminEmail().split(ConstUtils.COMMA)));
        weChatComponent.sendWeChatToAll(title,content,appDetailVO.getWeChatList());
    }

    /**
     * 单个分片连接数报警
     * @param instanceStats
     * @param appDetailVO
     * @param appClientConnThreshold
     */
    private void alertInstanceClientConn(final InstanceStats instanceStats, final AppDetailVO appDetailVO,
            final int appClientConnThreshold) {
        String instanceHostPort = instanceStats.getIp() + ":" + instanceStats.getPort();
        String content = String.format("分片(%s,应用(%s))客户端连接数报警-预设%s-现已达到%s-请及时关注", instanceHostPort,
                instanceStats.getAppId(), appClientConnThreshold, instanceStats.getCurrConnections());
        String title = "CacheCloud系统-分片客户端连接数报警";
        logger.warn("instance title {}", title);
        logger.warn("instace content {}", content);
        appAlertRecordService.saveAlertInfoByType(AlertTypeEnum.APP_SHARD_CLENT_CONNECTION, title, content, appDetailVO, instanceStats);
        emailComponent.sendMail(title, content, appDetailVO.getEmailList(),
                Arrays.asList(emailComponent.getAdminEmail().split(ConstUtils.COMMA)));
        weChatComponent.sendWeChatToAll(title,content,appDetailVO.getWeChatList());
    }

    public void setAppStatsCenter(AppStatsCenter appStatsCenter) {
        this.appStatsCenter = appStatsCenter;
    }

    public void setInstanceStatsCenter(InstanceStatsCenter instanceStatsCenter) {
        this.instanceStatsCenter = instanceStatsCenter;
    }

}
