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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.ExecuteException;
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 org.springframework.util.StringUtils;

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


public class IOSDeviceInfoByPackageThread extends Thread {

    private DebuggerDeviceInfo info;

    private OutputStream cpuOutPutStream;

    private String cpuFileName;

    private OutputStream memoOutPutStream;

    private String memoFileName;

    private OutputStream flowOutPutStream;

    private String flowFileName;

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

    private Process process;

    private Long oldDownload;

    private int cpuNum = 1;

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

    public int getDeviceCpuNum(){
        return this.cpuNum;
    }

    public IOSDeviceInfoByPackageThread(DebuggerDeviceInfo info) {
        this.info = info;
        getCpuNum();
        List<String> cmds = new ArrayList<>();
        cmds.add("sib");
        cmds.add("-u");
        cmds.add(info.getDeviceId());
        cmds.add("perfmon");
        cmds.add("-b");
        cmds.add(info.getAppPackage());
        try {
            process = new ProcessBuilder().command(cmds).redirectErrorStream(true).start();
        } catch (IOException e) {
            logger.error("开启性能获取失败", e);
        }
        String stfPath = SpringUtils.getProperties("nk.mobile-computer.stfPath");
        File dir = new File(stfPath + "/perInfoTmp/");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            cpuFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_cpu.txt";
            memoFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_memo.txt";
            flowFileName = dir.getAbsolutePath() + "/" + info.getCaseId() + "_flow.txt";
            cpuOutPutStream = new FileOutputStream(cpuFileName);
            cpuOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            cpuOutPutStream.flush();
            memoOutPutStream = new FileOutputStream(memoFileName);
            memoOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            memoOutPutStream.flush();
            flowOutPutStream = new FileOutputStream(flowFileName);
            flowOutPutStream.write("0".getBytes(StandardCharsets.UTF_8));
            flowOutPutStream.flush();
        } catch (IOException e) {
            logger.error("创建应用数据文件失败", e);
            throw new ParamMistakeException("创建应用数据文件失败");
        }
    }

    @Override
    public void run() {
        logger.info("开始任务Id【{}】的cpu、memo、flow数据的获取", info.getCaseId());
        String line = null;
        if (null != process) {
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                JSONObject jsonObject = null;
                while ((line = reader.readLine()) != null) {
                    if (line.trim().startsWith("get pid")) {
                        logger.info("获取到应用【{}】的pid:{}",info.getAppPackage(),line);
                        continue;
                    }
                    if (line.trim().startsWith("can't find pid")){
                        logger.warn("无法找到应用【{}】的pid:{}",info.getAppPackage(),line);
                        continue;
                    }
                    try {
                        jsonObject = JSONObject.parseObject(line, JSONObject.class);
                    } catch (Exception e) {
                        logger.error("Json转换失败", e);
                        throw new ExecuteException("Json转换失败");
                    }
                    switch (jsonObject.getString("type")) {
                        case "sys_cpu":
                            Double cpuValue = jsonObject.getDoubleValue("total_load");
                            if (cpuValue == null) {
                                cpuOutPutStream.write(("," + 0).getBytes(StandardCharsets.UTF_8));
                                cpuOutPutStream.flush();
                            } else {
                                float v = cpuValue.floatValue() / cpuNum;
                                String formatValue = this.format.format(v);
                                cpuOutPutStream.write(("," + formatValue).getBytes(StandardCharsets.UTF_8));
                                cpuOutPutStream.flush();
                            }
                            break;
                        case "sys_mem":
                            Long memoValue = jsonObject.getLongValue("app_memory");
                            if (memoValue == null) {
                                memoOutPutStream.write(("," + 0).getBytes(StandardCharsets.UTF_8));
                                memoOutPutStream.flush();
                            } else {
                                float v = memoValue.floatValue() / 1024f;
                                String formatValue = this.format.format(v);
                                memoOutPutStream.write(("," + formatValue).getBytes(StandardCharsets.UTF_8));
                                memoOutPutStream.flush();
                            }
                            break;
                        case "sys_network":
                            Long downFlow = jsonObject.getLongValue("bytes_in");
                            if (downFlow != null) {
                                if (null != oldDownload) {
                                    Long flow = downFlow - oldDownload;
                                    double v = flow.doubleValue() / 1024 / 1024;
                                    String formatValue = this.format.format(v);
                                    flowOutPutStream.write(("," + formatValue).getBytes(StandardCharsets.UTF_8));
                                    flowOutPutStream.flush();
                                }
                                oldDownload = downFlow;
                            }
                            break;
                        default:
                            break;
                    }
                    logger.debug("收集设备【{}】应用【{}】数据中。。。。。,任务Id：{}", info.getDeviceId(), info.getAppPackage(), info.getCaseId());

                }
            } catch (IOException e) {
                logger.error("设备【{}】读取性能数据出错", info.getDeviceId(), e);
            }
        }
        logger.info("收集设备【{}】应用【{}】数据结束,任务id:{}。。。。。。", info.getDeviceId(), info.getAppPackage(), info.getCaseId());
    }

    public String stopThread() {
        logger.info("收到设备【{}】应用【{}】性能数据停止请求,任务id:{}。。。。。。", info.getDeviceId(), info.getAppPackage(), info.getCaseId());
        if (null != process) {
            process.destroyForcibly();
        }
        try {
            cpuOutPutStream.close();
            memoOutPutStream.close();
            flowOutPutStream.close();
        } catch (IOException e) {
            logger.error("文件流关闭异常", e);
        }
        String stfPath = SpringUtils.getProperties("nk.mobile-computer.stfPath");
        File dir = new File(stfPath + "/perInfoTmp/");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir.getAbsolutePath() + "/" + info.getCaseId() + "_app.txt");
        byte[] data = new byte[4096];
        int length = 0;
        File cpuFile = new File(cpuFileName);
        File memoFile = new File(memoFileName);
        File flowFile = new File(flowFileName);
        FileOutputStream fileOutputStream = null;
        FileInputStream cpuFileInputStream = null;
        FileInputStream memoFileInputStream = null;
        FileInputStream flowFileInputStream = 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("]}".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应用{}性能文件，任务信息：{}", info.getAppPackage(),  JSON.toJSONString(info));
            attachment = HttpUtils.upload(serverAddr + publicUploadAddr, file.getAbsolutePath(), info.getTenantId(), info.getCaseId(), FileBusinessTypeEnum.MOBILE_TASK_APP_PERFORMANCE.getCode());
            logger.info("任务Id：{}，上传应用的数据成功！文件id:{}", info.getCaseId(),attachment.getUrlPath());
            return attachment.getUrlPath();
        } catch (Exception e) {
            logger.warn("caseId：{}，上传应用数据失败！", 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 (cpuFile.exists()) {
                cpuFile.delete();
            }
            if (memoFile.exists()) {
                memoFile.delete();
            }
            if (flowFile.exists()) {
                flowFile.delete();
            }
            if (null != fileOutputStream) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流失败，e,{}",e);
                }
            }
        }

    }
    private void getCpuNum() {
        List<String> cmds = new ArrayList<>();
        cmds.add("tidevice");
        cmds.add("-u");
        cmds.add(info.getDeviceId());
        cmds.add("perf");
        cmds.add("-o");
        cmds.add("cpu");
        cmds.add("-B");
        cmds.add(info.getAppPackage());
        try {
            Process cpuNumProcess = new ProcessBuilder().command(cmds).redirectErrorStream(true).start();
            InputStream inputStream = cpuNumProcess.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            JSONObject jsonObject = null;
            String line = null;
            while ((line = reader.readLine()) != null) {
                logger.info(line);
                if (StringUtils.hasText(line)) {
                    String key = line.substring(0, line.indexOf(" "));
                    String value = line.replace(key + " ", "");
                    try {
                        jsonObject = JSONObject.parseObject(value, JSONObject.class);
                        cpuNum = jsonObject.getInteger("count");
                        logger.info("cpu核心：{}", cpuNum);
                        break;
                    } catch (Exception e) {
                        logger.error("Json转换失败", e);
                        throw new ExecuteException("Json转换失败");
                    }
                }
            }
            cpuNumProcess.destroyForcibly();
        } catch (IOException e) {
            logger.error("获取cpu核心数失败", e);
            throw new ExecuteException("获取cpu核心数失败");
        }

    }

}
