package com.priusis;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.priusis.dto.RegisterParamDto;
import com.priusis.util.WinExecuteUtils;
import com.priusis.vo.MqttRpcDataMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@EnableScheduling
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, SecurityAutoConfiguration.class})
public class ApqRegisterApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApqRegisterApplication.class, args);
    }

    // "params":
    // {
    //    "type":1
    //    "programs": [
    //      {
    //          "name":"qq"
    //      }
    //    ]
    // }

    // 一分钟一次上报
    private final Long FIXED_DELAY = 60000L;

    @Autowired
    private RestTemplate restTemplate;

    @Scheduled(fixedDelay = 60000L)
    protected void registerProgramTask() {
        log.info("软件检测上报=================");
        // 获取软件检测监控配置 params == data
        ResponseEntity<MqttRpcDataMessage> forEntity = null;
        try {
            forEntity = restTemplate.getForEntity("http://localhost:8765/rpc_cmd/register", MqttRpcDataMessage.class);
        } catch (RestClientException e) {
            log.error("软件检测上报异常", e.getMessage());
        }
        if (null != forEntity) {
            MqttRpcDataMessage body = forEntity.getBody();
            String params = body.getParams();

            if (StrUtil.isNotBlank(params)) {
                Long sendTime = body.getSendTime();
                long current = System.currentTimeMillis();
                RegisterParamDto registerParamDto = JSONUtil.toBean(params, RegisterParamDto.class);

                // 收到软件检测下发请求
                log.info("收到软件检测下发请求, sendTime:{}, params:{}", sendTime, params);

                int type = registerParamDto.getType();
                if (type == 1) {
                    List<String> loadProgramList = null;
                    try {
                        loadProgramList = loadProgramList();
                    } catch (IOException e) {
                        log.error("获取软件清单异常", e);
                    }

                    if (null == loadProgramList) {
                        return;
                    }

                    List<RegisterParamDto.RegisterDetailParamDto> programs = registerParamDto.getPrograms();
                    // 上报软件检测监控数据
                    Map mapRequest = new HashMap();
                    for (RegisterParamDto.RegisterDetailParamDto program : programs) {
                        String name = program.getName().trim().toLowerCase();

                        if (loadProgramList.contains(name)) {
                            // 杀进程
                            try {
                                WinExecuteUtils.killProc(name);
                            } catch (Exception e) {
                                log.error("杀进程异常", e);
                            }

                            // 上报黑名单异常
                            mapRequest.put(name, "1");
                        }
                    }
                    // 上报黑名单异常
                    if (mapRequest.size() > 0) {
                        Map eventMapRequest = new HashMap();
                        eventMapRequest.put("methodName", "BlackList");
                        eventMapRequest.put("params", mapRequest);
                        Map map = restTemplate.postForObject("http://localhost:8765/uplink_event/oc-client", eventMapRequest, Map.class);
                        log.info("存在软件检测接口扫码告警，上报告警事件: mapData:{}, ret:{}", mapRequest, map);
                    }

                    // 上报黑名单属性 todo
                }
            } else {
                log.info("未获取到获取软件检测监控配置");
            }
        } else {
            log.info("未获取到获取软件检测监控配置");
        }


    }

    /**
     * 获取软件清单
     *
     * @return
     * @throws IOException
     */
    protected List<String> loadProgramList() throws IOException {
        List<String> programs = new ArrayList<>();
        Process process = Runtime.getRuntime()
                .exec("cmd /c reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
            String key;
            while ((key = reader.readLine()) != null) {
                List<String> info = queryProgramInfo(key);
                programs.addAll(info);
            }
            process.destroy();
        }
        return programs;
    }

    private List<String> queryProgramInfo(String key) throws IOException {
        List<String> info = new ArrayList<>();
        Process process = Runtime.getRuntime().exec("cmd /c reg query " + key);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
            reader.readLine();
            reader.readLine();
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.startsWith("DisplayName")) {
                    info.add(line.replace("DisplayName", "").replace("REG_SZ", "").trim().toLowerCase());
                }
            }
            process.destroy();
        }
        return info;
    }
}
