package com.priusis;

import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.system.oshi.OshiUtil;
import com.priusis.util.MacAddrUtil;
import com.priusis.vo.ApqInfoDataVo;
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.RestTemplate;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HWPartition;
import oshi.util.FormatUtil;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private RestTemplate restTemplate;

    private int runningIndex = 0;

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

    // 30秒一次上报
    @Scheduled(fixedDelay = 30000L)
    protected void controlProgramTask() {
        log.info("设备实时数据采集上报=================");
        runningIndex++;
        boolean isNoneEven = runningIndex % 2 == 0;

        // 获取采集配置，数据上报频率 params == data
        ResponseEntity<MqttRpcDataMessage> forEntity = null;
        Map<String, Integer> mapParams = null;
        try {
            forEntity = restTemplate.getForEntity("http://localhost:8765/rpc_cmd/info", MqttRpcDataMessage.class);
            if (null != forEntity) {
                MqttRpcDataMessage body = forEntity.getBody();
                String params = body.getParams();

                if (StrUtil.isNotBlank(params)) {
                    List<ApqInfoDataVo> apqInfoDataVos = JSONUtil.toList(params, ApqInfoDataVo.class);
                    mapParams = new HashMap<>();
                    for (ApqInfoDataVo apqInfoDataVo : apqInfoDataVos) {
                        mapParams.put(apqInfoDataVo.getCode(), apqInfoDataVo.getFrequency());

                    }
                }
            }
        } catch (Exception e) {
            log.error("采集数据异常", e);
        }


        String operatingSystem = "operatingSystem";
        String mac = "mac";
        String baseboard = "baseboard";
        String ip = "ip";
        String cpuModel = "cpuModel";
        String cpuLoad = "cpuLoad";
        String cpuTemp = "cpuTemp";
        String memoryCap = "memoryCap";
        String memoryAvailable = "memoryAvailable";
        String diskModel = "diskModel";
        String diskCap = "diskCap";

        try {
            // 上报PC实时信息
            Map<String, Object> data = MapUtil.<String, Object>builder()
                    .put(isNeedCollection(isNoneEven, operatingSystem, mapParams), operatingSystem, OshiUtil.getOs().toString())
                    .put(isNeedCollection(isNoneEven, mac, mapParams), mac, MacAddrUtil.get())
                    .put(isNeedCollection(isNoneEven, baseboard, mapParams), baseboard, OshiUtil.getSystem().getBaseboard().getManufacturer() + " " + OshiUtil.getSystem().getBaseboard().getVersion())
                    .put(isNeedCollection(isNoneEven, ip, mapParams), ip, InetAddress.getLocalHost().getHostAddress())
                    .put(isNeedCollection(isNoneEven, cpuModel, mapParams), cpuModel, OshiUtil.getCpuInfo(0).getCpuModel())
                    .put(isNeedCollection(isNoneEven, cpuTemp, mapParams), cpuTemp, OshiUtil.getSensors().getCpuTemperature())
                    .put(isNeedCollection(isNoneEven, cpuLoad, mapParams), cpuLoad, getCpuUsed())
                    .put(isNeedCollection(isNoneEven, memoryCap, mapParams), memoryCap, DataSizeUtil.format(OshiUtil.getMemory().getTotal()))
                    .put(isNeedCollection(isNoneEven, memoryAvailable, mapParams), memoryAvailable, DataSizeUtil.format(OshiUtil.getMemory().getAvailable()))
                    .put(isNeedCollection(isNoneEven, diskModel, mapParams), diskModel, OshiUtil.getHardware().getDiskStores()[0].getModel())
                    .put(isNeedCollection(isNoneEven, diskCap, mapParams), diskCap, DataSizeUtil.format(OshiUtil.getHardware().getDiskStores()[0].getSize()))
                    .build();
            Map mapR = restTemplate.postForObject("http://localhost:8765/uplink/oc-client", data, Map.class);
            log.info("采集数据，上报属性: mapData:{}, ret:{}", data, mapR);
        } catch (Exception e) {
            log.error("采集数据异常", e);
        }
    }

    private boolean isNeedCollection(boolean isNoneEven, String key, Map<String, Integer> mapParams) {
        if (null != mapParams && mapParams.containsKey(key)) {
            return (!isNoneEven || mapParams.get(key) != 30);
        } else {
            return isNoneEven;
        }
    }

    public static void main2(String[] args) throws InterruptedException {
        /*String data = "[" +
                "{\"code\":\"cpuLoad\",\"name\":\"CPU负载\",\"frequency\":30}," +
                "{\"code\":\"cpuTemp\",\"name\":\"CPU温度\",\"frequency\":30}," +
                "{\"code\":\"mac\",\"name\":\"MAC地址\",\"frequency\":30}," +
                "{\"code\":\"memoryCap\",\"name\":\"内存容量\",\"frequency\":30}," +
                "{\"code\":\"diskCap\",\"name\":\"硬盘容量\",\"frequency\":30}," +
                "{\"code\":\"diskModel\",\"name\":\"硬盘型号\",\"frequency\":60}," +
                "]";
        List<ApqInfoDataVo> apqInfoDataVoss = new ArrayList<>();
        ApqInfoDataVo apqInfoDataVo = new ApqInfoDataVo();
        apqInfoDataVo.setCode("diskModel");
        apqInfoDataVo.setName("硬盘型号");
        apqInfoDataVo.setFrequency(60);
        apqInfoDataVoss.add(apqInfoDataVo);

        ApqInfoDataVo apqInfoDataVo2 = new ApqInfoDataVo();
        apqInfoDataVo2.setCode("memoryCap");
        apqInfoDataVo2.setName("内存容量");
        apqInfoDataVo2.setFrequency(30);
        apqInfoDataVoss.add(apqInfoDataVo2);

        String s = JSONUtil.toJsonStr(apqInfoDataVoss);
        System.out.println(s);

        List<ApqInfoDataVo> apqInfoDataVos = JSONUtil.toList(data, ApqInfoDataVo.class);
        List<Map> apqInfoDataVos2 = JSONUtil.toList(data, Map.class);*/

        System.out.println(OshiUtil.getSensors().getCpuTemperature());
        System.out.println(OshiUtil.getHardware().getDiskStores()[0].getModel());
        System.out.println(DataSizeUtil.format(OshiUtil.getHardware().getDiskStores()[0].getReads()));
        //System.out.println("CPU内存使用率:" + new DecimalFormat("#.##%").format((OshiUtil.getMemory().getAvailable() * 1.0 / OshiUtil.getMemory().getTotal())));

        while (true) {
            //System.out.println("CPU负载:" + new DecimalFormat("#.##%").format(OshiUtil.getCpuInfo().getUsed() / 100));
            //System.out.println("硬盘剩余:" + OshiUtil.getHardware().getDiskStores()[0].getWriteBytes());

            System.out.println(getCpuUsed());

            Thread.sleep(3);
        }
    }

    public static double getCpuUsed() {
        SystemInfo systemInfo = new SystemInfo();
        CentralProcessor processor = systemInfo.getHardware().getProcessor();
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        //System.out.println("----------------cpu信息----------------");
        //System.out.println("cpu核数:" + processor.getLogicalProcessorCount());
        //System.out.println("cpu系统使用率:" + new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));
        //System.out.println("cpu用户使用率:" + new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));
        //System.out.println("cpu当前等待率:" + new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));
        //System.out.println("cpu当前使用率:" + new DecimalFormat("#.##%").format(1.0-(idle * 1.0 / totalCpu)));

        return new BigDecimal((1.0 - (idle * 1.0 / totalCpu)) * 100).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
    }

    private static void printDisks(List<HWDiskStore> list) {
        System.out.println("Disks:");
        for (HWDiskStore disk : list) {
            boolean readwrite = disk.getReads() > 0 || disk.getWrites() > 0;
            System.out.format(" %s: (model: %s - S/N: %s) size: %s, reads: %s (%s), writes: %s (%s), xfer: %s ms%n",
                    disk.getName(), disk.getModel(), disk.getSerial(),
                    disk.getSize() > 0 ? FormatUtil.formatBytesDecimal(disk.getSize()) : "?",
                    readwrite ? disk.getReads() : "?", readwrite ? FormatUtil.formatBytes(disk.getReadBytes()) : "?",
                    readwrite ? disk.getWrites() : "?", readwrite ? FormatUtil.formatBytes(disk.getWriteBytes()) : "?",
                    readwrite ? disk.getTransferTime() : "?");
            List<HWPartition> partitions = Arrays.asList(disk.getPartitions());
            if (partitions == null) {
                // TODO Remove when all OS's implemented
                continue;
            }
            for (HWPartition part : partitions) {
                System.out.format(" |-- %s: %s (%s) Maj:Min=%d:%d, size: %s%s%n", part.getIdentification(),
                        part.getName(), part.getType(), part.getMajor(), part.getMinor(),
                        FormatUtil.formatBytesDecimal(part.getSize()),
                        part.getMountPoint().isEmpty() ? "" : " @ " + part.getMountPoint());
            }
        }
    }

}
