package net.northking.cctp.upperComputer.service.thread;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.northking.cctp.upperComputer.deviceManager.UpperComputerManager;
import net.northking.cctp.upperComputer.enums.FileBusinessTypeEnum;
import net.northking.cctp.upperComputer.entity.Attachment;
import net.northking.cctp.upperComputer.entity.DebuggerDeviceInfo;
import net.northking.cctp.upperComputer.exception.ParamMistakeException;
import net.northking.cctp.upperComputer.utils.HttpUtils;
import net.northking.cctp.upperComputer.utils.SpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class IOSDeviceAllInfoThread extends Thread {

    private DebuggerDeviceInfo info;

    private OutputStream cpuOutPutStream;

    private String cpuFileName;

    private OutputStream memoOutPutStream;

    private String memoFileName;

    private OutputStream flowOutPutStream;

    private String flowFileName;

    private OutputStream temperatureOutPutStream;

    private String temperatureFileName;

    private DecimalFormat format = new DecimalFormat("0.00");

    private TemperatureThread temperatureThread;

    private Process process;

    private Long oldDownload = 0l;

    private Logger logger = LoggerFactory.getLogger(IOSDeviceAllInfoThread.class);

    private int cpuNum = 1;

    public IOSDeviceAllInfoThread(DebuggerDeviceInfo info, int deviceCpuNum) {
        this.info = info;
        cpuNum = deviceCpuNum;
        List<String> cmds = new ArrayList<>();
        cmds.add("sib");
        cmds.add("-u");
        cmds.add(info.getDeviceId());
        cmds.add("perfmon");
        try {
            process = new ProcessBuilder().command(cmds).redirectErrorStream(true).start();
        } catch (IOException e) {
            logger.error("开启性能获取失败", e);
        }
        logger.info("设备性能开始完毕。。。。。。。cpuNum:{},任务id:{}",cpuNum,info.getCaseId());
        String stfPath = UpperComputerManager.getInstance().getApplicationPath();
        File dir = new File(stfPath + "/perInfoTmp/");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            cpuFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_all_cpu.txt";
            memoFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_all_memo.txt";
            flowFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_all_flow.txt";
            temperatureFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_all_temperature.txt";
            cpuOutPutStream = new FileOutputStream(cpuFileName);
            cpuOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            memoOutPutStream = new FileOutputStream(memoFileName);
            memoOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            flowOutPutStream = new FileOutputStream(flowFileName);
            flowOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            temperatureOutPutStream = new FileOutputStream(temperatureFileName);
            temperatureThread = new TemperatureThread(info.getDeviceId());
            temperatureThread.start();
        } catch (IOException e) {
            logger.error("创建设备数据文件失败", e);
            throw new ParamMistakeException("创建设备数据文件失败");
        }
    }


    @Override
    public void run() {
        logger.info("开始任务Id【{}】的cpu、memo、flow数据的获取", info.getCaseId());
        String line = null;
        long flow = 0l;
        String format = null;
        if (null != process) {
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            int failCount = 0;
            try {
                JSONObject jsonObject = null;
                while (((line = reader.readLine()) != null) && !isInterrupted()) {
                    logger.info(line);
                    if (line != null) {
                        JSONObject result = JSON.parseObject(line.trim(), JSONObject.class);
                        switch (result.getString("type")) {
                            case "sys_cpu":
                                Double total = result.getDouble("total_load");
                                double cpu = total / cpuNum;
                                format = this.format.format(cpu);
                                cpuOutPutStream.write(("," + format).getBytes(StandardCharsets.UTF_8));
                                cpuOutPutStream.flush();
                                break;
                            case "sys_mem":
                                Integer usedMemory = result.getInteger("used_memory");
                                if (null == usedMemory) {
                                    memoOutPutStream.write((",0").getBytes(StandardCharsets.UTF_8));
                                } else {
                                    float memo = usedMemory / 1024f;
                                    format = this.format.format(memo);
                                    memoOutPutStream.write(("," + format).getBytes(StandardCharsets.UTF_8));
                                }
                                memoOutPutStream.flush();
                                break;
                            case "sys_network":
                                Long bytesIn = result.getLong("bytes_in");
                                if (oldDownload == 0) {
                                    oldDownload = bytesIn;
                                } else {
                                    flow = bytesIn - oldDownload;
                                    oldDownload = bytesIn;
                                    if (flow > 0) {
                                        format = this.format.format(flow / 1024f / 1024f);
                                        float value = Float.parseFloat(format);
                                        flowOutPutStream.write(("," + format).getBytes(StandardCharsets.UTF_8));
                                        flowOutPutStream.flush();
                                    }
                                }
                                break;
                            default:
                                continue;
                        }
                    }
                }
            } catch (EOFException e) {
                logger.error("设备【{}】读取性能数据停止异常：",info.getDeviceId(), e);
                stopThread();
            } catch (IOException e) {
                logger.error("设备【{}】读取性能数据出错", info.getDeviceId(), e);
                failCount++;
                if (failCount > 5) {
                    logger.error("设备【{}】get perf error > 3，中断读取：",info.getDeviceId(), e);
                    stopThread();
                }
            }
        }
        logger.info("收集设备【{}】性能数据结束,任务id:{}。。。。。。", info.getDeviceId(), info.getAppPackage(), info.getCaseId());
    }

    public String stopThread() {
        logger.info("收到设备【{}】的性能数据停止请求,任务id:{}。。。。。。", info.getDeviceId(), info.getCaseId());
        if (temperatureThread != null && temperatureThread.isAlive()) {
            temperatureThread.stopAndExit();
            temperatureThread = null;
        }
        if (null != process) {
            process.destroyForcibly();
        }
        try {
            cpuOutPutStream.close();
            memoOutPutStream.close();
            flowOutPutStream.close();
            temperatureOutPutStream.close();
        } catch (IOException e) {
            logger.error("文件流关闭异常", e);
        }
        String stfPath = UpperComputerManager.getInstance().getApplicationPath();
        File dir = new File(stfPath + "/perInfoTmp/");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir.getAbsolutePath() + "/" + info.getCaseId() + "_all.txt");
        byte[] data = new byte[4096];
        int length = 0;
        File cpuFile = new File(cpuFileName);
        File memoFile = new File(memoFileName);
        File flowFile = new File(flowFileName);
        File temperatureFile = new File(temperatureFileName);
        FileOutputStream fileOutputStream = null;
        FileInputStream cpuFileInputStream = null;
        FileInputStream memoFileInputStream = null;
        FileInputStream flowFileInputStream = null;
        FileInputStream temperatureInputStream = null;
        try {
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write("{\"cpuList\":[".getBytes(StandardCharsets.UTF_8));
            fileOutputStream.flush();
            cpuFileInputStream = new FileInputStream(cpuFile);
            while ((length = cpuFileInputStream.read(data, 0, data.length)) > 0) {
                fileOutputStream.write(data, 0, length);
                fileOutputStream.flush();
            }
            fileOutputStream.write("],\"memoList\":[".getBytes(StandardCharsets.UTF_8));
            fileOutputStream.flush();
            memoFileInputStream = new FileInputStream(memoFile);
            while ((length = memoFileInputStream.read(data, 0, data.length)) > 0) {
                fileOutputStream.write(data, 0, length);
                fileOutputStream.flush();
            }
            fileOutputStream.write("],\"flowList\":[".getBytes(StandardCharsets.UTF_8));
            flowFileInputStream = new FileInputStream(flowFile);
            while ((length = flowFileInputStream.read(data, 0, data.length)) > 0) {
                fileOutputStream.write(data, 0, length);
                fileOutputStream.flush();
            }
            fileOutputStream.write("],\"temperatureList\":[".getBytes(StandardCharsets.UTF_8));
            temperatureInputStream = new FileInputStream(temperatureFile);
            while ((length = temperatureInputStream.read(data, 0, data.length)) > 0) {
                fileOutputStream.write(data, 0, length);
                fileOutputStream.flush();
            }
            fileOutputStream.write("]}".getBytes(StandardCharsets.UTF_8));
            fileOutputStream.flush();
        } catch (IOException e) {
            logger.error("性能数据保存失败", e);
            return "";
        }
        //上传
        String serverAddr = SpringUtils.getProperties("nk.mobile-computer.serverAddr");
        String publicUploadAddr = SpringUtils.getProperties("nk.mobile-computer.publicUploadAddr");
        Attachment attachment = null;
        try {
            logger.info("开始上传ios设备性能文件，任务信息：{}",JSON.toJSONString(info));
            attachment = HttpUtils.upload(serverAddr + publicUploadAddr, file.getAbsolutePath(), info.getTenantId(),info.getCaseId(), FileBusinessTypeEnum.MOBILE_TASK_DEVICE_PERFORMANCE.getCode());
            logger.info("任务Id：{}，上传设备数据成功！文件id:{}", info.getCaseId(),attachment.getUrlPath());
            return attachment.getUrlPath();
        } catch (Exception e) {
            logger.warn("任务Id：{}，上传应用数据失败！", info.getCaseId());
            return "";
        }finally {
            if (null != cpuFileInputStream) {
                try {
                    cpuFileInputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
            if (null != memoFileInputStream) {
                try {
                    memoFileInputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
            if (null != flowFileInputStream) {
                try {
                    flowFileInputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
            if (null != temperatureInputStream) {
                try {
                    temperatureInputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
            if (cpuFile.exists()) {
                cpuFile.delete();
            }
            if (memoFile.exists()) {
                memoFile.delete();
            }
            if (flowFile.exists()) {
                flowFile.delete();
            }
            if (temperatureFile.exists()) {
                temperatureFile.delete();
            }
            if (null != fileOutputStream) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
        }

    }


    private class TemperatureThread extends Thread {

        List<String> cmds = new ArrayList<>();

        private Process process;

        private TemperatureThread(String uuid) {
            cmds.add("sib");
            cmds.add("-u");
            cmds.add(uuid);
            cmds.add("battery");
            try {
                process = new ProcessBuilder().command(cmds).redirectErrorStream(true).start();
            } catch (IOException e) {
                logger.error("开启性能获取失败", e);
            }
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    if (line != null) {
                        if (line.contains("Temperature")) {
                            String[] split = line.split(":");
                            float temperature = Float.parseFloat(split[1].trim()) / 100f;
                            String result = format.format(temperature);
                            temperatureOutPutStream.write((result).getBytes(StandardCharsets.UTF_8));
                            temperatureOutPutStream.flush();
                        }
                    }
                }
            } catch (Exception e) {
                logger.warn("读取温度出错", e);
                try {
                    temperatureOutPutStream.write(("0").getBytes(StandardCharsets.UTF_8));
                    temperatureOutPutStream.flush();
                } catch (IOException ex) {
                    logger.error("temperatureOutPutStream输入流写入出错，ex,{}",ex);
                }
            }
        }

        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    process = new ProcessBuilder().command(cmds).redirectErrorStream(true).start();
                } catch (IOException e) {
                    logger.error("开启性能获取失败", e);
                }
                InputStream inputStream = process.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line = null;
                try {
                    while ((line = reader.readLine()) != null) {
                        if (line != null) {
                            if (line.contains("Temperature")) {
                                String[] split = line.split(":");
                                float temperature = Float.parseFloat(split[1].trim()) / 100f;
                                String result = format.format(temperature);
                                temperatureOutPutStream.write((","+result).getBytes(StandardCharsets.UTF_8));
                                temperatureOutPutStream.flush();
                            }
                        }
                    }
                } catch (Exception e) {
                    logger.warn("读取温度出错", e);
                    continue;
                }
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

        private void stopAndExit() {
            interrupt();
        }
    }
}
