package com.docus.server.common.netty.client.handler;

import com.docus.core.util.DateUtil;
import com.docus.core.util.Func;
import com.docus.core.util.ListUtils;
import com.docus.core.util.json.JSON;
import com.docus.server.common.CommMsg;
import com.docus.server.common.netty.client.NettyClient;
import com.docus.server.common.netty.server.CollectorChannelCacheMap;
import com.docus.server.common.utils.StartUpExeUtils;
import com.docus.server.dto.scheduling.management.schcollector.task.SchCollectorTaskDTO;
import com.docus.server.vo.scheduling.management.schcollector.LoadSchCollectorVO;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.docus.server.common.MsgConstants.*;

@Slf4j
@AllArgsConstructor
@NoArgsConstructor
public class ClientHandler extends SimpleChannelInboundHandler<CommMsg<Serializable>> {

    private NettyClient nettyClient;

    @Override
    protected void channelRead0(ChannelHandlerContext context, CommMsg commMsg) throws Exception {

        String messageType = commMsg.getMessageType();
        String messageTime = commMsg.getMessageTime();
        String messageContent = (String) commMsg.getContent();

        log.info("======== 【终端客户端-收到调度器消息】, 消息时间={}, 消息类型={}, 消息内容={}", messageTime, messageType, messageContent + " ======== ");

        switch (messageType) {
            case TERMINATOR_RESTART:
                terminatorRestart(messageContent);
                break;
            case COLLECTOR_RESTART:
                collectorRestart(messageContent);
                break;
            case VIRTUAL_RESTART:
                virtualRestart(messageContent);
                break;
            case UPDATE_COLLECTOR_FILE:
                updateCollectorFile(messageContent);
                break;
            case UPDATE_COLLECTOR_CONFIG:
                updateCollectorConfig(messageContent);
                break;
            case SCH_DISTRIBUTE_TASKS:
                schDistributeTasks(commMsg, messageContent);
                break;
            case HAS_VALID_COLLECTOR:
                hasValidCollector(messageContent);
                break;
            case HAS_COLLECTOR_COUNT:
                hasCollectorCount(context, messageContent);
                break;
            default:
                break;
        }
    }

    private void hasCollectorCount(ChannelHandlerContext context, String messageContent) {
        log.info("【终端客户端-收到调度器消息】收到获取采集器数量命令，内容={}", messageContent);

        CollectorChannelCacheMap collectorChannelCacheMap = nettyClient.getCollectorChannelCacheMap();
        Map<String, Channel> collectorMap = collectorChannelCacheMap.getAll();

        String packageValue = nettyClient.getRedisMsg();
        List<LoadSchCollectorVO> redisLoadSchCollectors = JSON.fromJSONWithGeneric(packageValue, new TypeReference<List<LoadSchCollectorVO>>() {
        });

        List<LoadSchCollectorVO> objects = Lists.newArrayList();

        for (LoadSchCollectorVO loadSchCollectorVO : redisLoadSchCollectors) {
            if (collectorMap.containsKey(String.valueOf(loadSchCollectorVO.getCollectorId()))) {
                objects.add(loadSchCollectorVO);
            }
        }

        CommMsg<Serializable> collectorCountMsg = CommMsg.builder()
            .messageType(HAS_COLLECTOR_COUNT)
            .messageTime(DateUtil.formatDateTime(new Date()))
            .content(JSON.toJSON(objects))
            .build();

        context.channel().writeAndFlush(collectorCountMsg);
    }

    private void hasValidCollector(String messageContent) {
        log.info("【终端客户端-收到调度器消息】是否有可用类型的采集器命令，内容={}", messageContent);
    }

    private void schDistributeTasks(CommMsg commMsg, String messageContent) throws Exception {
        log.info("【终端客户端-收到调度器消息】收到采集调度器下发任务命令，内容={}", messageContent);

        //下发任务： 判断这个任务采集器类型在指定目录是否存在、
        //如果不存在：下拉该采集器类型最新的版本更新包到指定的部署路径，并且启动该exe采集器，将任务tcp给对应采集器
        //如果存在：

        SchCollectorTaskDTO schCollectorTaskDTO = JSON.fromJSON(messageContent, SchCollectorTaskDTO.class);
        String collectorId = schCollectorTaskDTO.getTaskInfo().getTasks().get(0).getCollectorId();

        Long compareCollectorId = Long.valueOf(collectorId);

        String packageValue = nettyClient.getRedisMsg();
        CollectorChannelCacheMap collectorChannelCacheMap = nettyClient.getCollectorChannelCacheMap();
        String saveCollectorPackagePath = nettyClient.getSaveCollectorPackagePath();

        if (Func.isBlank(packageValue)) {
            System.out.println("packageValue 为空" + packageValue);
            return;
        }

        List<LoadSchCollectorVO> redisLoadSchCollectors = JSON.fromJSONWithGeneric(packageValue, new TypeReference<List<LoadSchCollectorVO>>() {
        });

        Map<Long, LoadSchCollectorVO> collectorVoMap = ListUtils.toMap(redisLoadSchCollectors, LoadSchCollectorVO::getCollectorId);

        if (collectorVoMap.containsKey(compareCollectorId)) {
            LoadSchCollectorVO loadSchCollectorVO = collectorVoMap.get(compareCollectorId);
            String processName = loadSchCollectorVO.getProcessName();

            if (Func.isNotBlank(processName)) {
                boolean isExistProcess = StartUpExeUtils.checkProcessOnly(processName);
                //存在指定采集器id进程
                if (isExistProcess) {
                    collectorChannelCacheMap.writeAndFlush(collectorId, commMsg);
                } else {
                    //不存在进程，则启动指定采集器进程,等待启动完成下发任务
                    StartUpExeUtils.startUpExeOnly(saveCollectorPackagePath + collectorId + "\\collector\\" + processName);

                    nettyClient.publishEvent(collectorId, commMsg);
                }
            }
        }
    }

    private void updateCollectorConfig(String messageContent) {
        log.info("【终端客户端-收到调度器消息】收到更新采集器配置命令，内容={}", messageContent);
    }

    private void updateCollectorFile(String messageContent) {
        log.info("【终端客户端-收到调度器消息】收到更新采集器文件命令，内容={}", messageContent);
    }

    private void virtualRestart(String messageContent) throws Exception {
        log.info("【终端客户端-收到调度器消息】收到虚拟机重启命令，内容={}", messageContent);
        String result = StartUpExeUtils.restartComputer();
        CommMsg<Serializable> collectorRestartMsg = CommMsg.builder()
            .content(result)
            .messageTime(DateUtil.formatDateTime(new Date()))
            .messageType(VIRTUAL_RESTART)
            .build();
        nettyClient.sendMessage(collectorRestartMsg);
    }

    private void collectorRestart(String messageContent) {
        log.info("【终端客户端-收到调度器消息】收到采集器重启命令，内容={}", messageContent);
        String packageValue = nettyClient.getRedisMsg();
        String saveCollectorPackagePath = nettyClient.getSaveCollectorPackagePath();
        List<LoadSchCollectorVO> redisLoadSchCollectors = JSON.fromJSONWithGeneric(packageValue, new TypeReference<List<LoadSchCollectorVO>>() {
        });

        Map<Long, LoadSchCollectorVO> collectorVoMap = ListUtils.toMap(redisLoadSchCollectors, LoadSchCollectorVO::getCollectorId);
        Long collectorId = Long.valueOf(messageContent);

        if (collectorVoMap.containsKey(collectorId)) {
            LoadSchCollectorVO loadSchCollectorVO = collectorVoMap.get(collectorId);
            String processName = loadSchCollectorVO.getProcessName();

            if (Func.isNotBlank(processName)) {
                boolean isExistProcess = StartUpExeUtils.checkProcessOnly(processName);
                //存在指定采集器id进程
                if (isExistProcess) {
                    boolean result = StartUpExeUtils.startUpExe(saveCollectorPackagePath + collectorId + "\\collector\\" + processName, processName);

                    CommMsg<Serializable> collectorRestartMsg = CommMsg.builder()
                        .content(result)
                        .messageTime(DateUtil.formatDateTime(new Date()))
                        .messageType(COLLECTOR_RESTART)
                        .build();
                    nettyClient.sendMessage(collectorRestartMsg);
                }
            }
        }
    }

    private void terminatorRestart(String messageContent) throws Exception {
        log.info("【终端客户端-收到调度器消息】接受到终端重启命令，内容={}", messageContent);
        String result = StartUpExeUtils.restartTerminal(nettyClient.getTerminalRestartBat());

        CommMsg<Serializable> terminatorRestartMsg = CommMsg.builder()
            .content(result)
            .messageTime(DateUtil.formatDateTime(new Date()))
            .messageType(TERMINATOR_RESTART)
            .build();

        nettyClient.sendMessage(terminatorRestartMsg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        Channel channel = ctx.channel();
        if (channel.isActive()) {
            ctx.close();
        }
        super.exceptionCaught(ctx, cause);
    }
}
