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

import net.northking.cctp.upperComputer.deviceManager.AndroidDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.UpperComputerManager;
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
import net.northking.cctp.upperComputer.driver.adb.AdbTransport;
import net.northking.cctp.upperComputer.enums.FileBusinessTypeEnum;
import net.northking.cctp.upperComputer.entity.Attachment;
import net.northking.cctp.upperComputer.utils.HttpUtils;
import net.northking.cctp.upperComputer.utils.SessionUtils;
import net.northking.cctp.upperComputer.utils.SpringUtils;
import net.northking.cctp.upperComputer.webSocket.entity.CmdRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 录屏线程
 */
public class AndroidLogThread extends Thread{

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

    private String serial;

    private AdbTransport adbTransport;

    private Session session;

    private AdbDevice adbDevice;

    private String logFilePath;

    private CmdRequest cmdRequest;

    private boolean alive;

    public String getLogFilePath() {
        return logFilePath;
    }

    public AndroidLogThread(String serial, AdbDevice adbDevice, Session session, CmdRequest cmdRequest, String logPath){
        this.serial = serial;
        this.adbDevice = adbDevice;
        this.session = session;
        this.cmdRequest = cmdRequest;
        this.logFilePath = logPath;
        this.alive = true;
        setName("[" + serial+"]-log");
    }

    @Override
    public void run() {
        if (logFilePath == null) {
            String applicationPath = UpperComputerManager.getInstance().getApplicationPath();
            File logPath = new File(applicationPath + "/logTmp");
            if (!logPath.exists()) {
                logPath.mkdirs();
            }
            SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
            String dateFormat = format.format(new Date());
            logFilePath = logPath.getAbsolutePath() + "/" + serial + "_" + dateFormat + ".log";
        }
        logger.info("[" +serial+ "]日志开启，时间:{}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        adbTransport = AndroidDeviceManager.getInstance().getAdb().shell(adbDevice,"logcat ");
        BufferedReader bi = null;
        FileWriter fw = null;
        try {
            bi = new BufferedReader(new InputStreamReader(adbTransport.getInputStream()));
            File logFile = new File(logFilePath);
            if (!logFile.exists()) {
                logFile.createNewFile();
            }
            logger.debug("[" +serial+ "]日志临时位置:{}",logFilePath);
            fw = new FileWriter(logFile);
            String line;
            StringBuilder sb = new StringBuilder();
            Map<String, Object> result = new HashMap<>();
            //匹配以MM-dd hh:mm:ss开头的正则表达式
            String timePre1 = "^(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1])\\s+(2[0-3]|[0-1]\\d):[0-5]\\d:[0-5]\\d";
            Pattern p = Pattern.compile(timePre1);
            Matcher matcher = null;
            while (((line = bi.readLine()) != null) && alive) {
                fw.write(line + "\r\n");
                //实时日志信息进行封装
                matcher = p.matcher(line);
                //是日志的开头
                if (matcher.find()) {
                    //将上一条的信息实时返回并清空
                    if (sb != null && sb.length() > 0) {
                        sb.delete(sb.length()-1,sb.length());
                        result.put("message",sb.toString());
                        SessionUtils.sendContinuousData(session, cmdRequest, result, "获取实时日志信息成功");
                        result.clear();
                        sb.delete(0,sb.length());
                    }
                    //存储本次信息
                    String[] split = line.split("\\s+");
                    if (split.length >= 6) {
                        String time = split[0] + " " + split[1];
                        String pid = split[2];
                        String tid = split[3];
                        String level = transLevelData(split[4]);
                        String tag = split[5].replace(":","");
                        int index = 6;
                        String msg = null;
                        while (index < split.length) {
                            if (!":".equals(split[index])) {
                                msg = line.substring(line.indexOf(split[5]));
                                break;
                            }
                            index++;
                        }
                        result.put("date",time);
                        result.put("pid",pid);
                        result.put("tid",tid);
                        result.put("level",level);
                        result.put("tag",tag);
                        sb.append(msg+" ");
                    }else {
                        logger.warn("日志信息解析格式不符，split："+split.length);
                        logger.warn("line："+line);
                    }
                }else if (line.contains("beginning of")){ //跳过日志的分区标志行
                    continue;
                }else {
                    sb.append(line+" "); //上条日志的msg分了多行
                }
            }
            //将最后一条的信息实时返回并清空
            if (sb != null && sb.length() > 0) {
                sb.delete(sb.length()-1,sb.length());
                result.put("message",sb.toString());
                SessionUtils.sendSuccessData(session, cmdRequest, result, "获取实时日志信息成功");
                result.clear();
                sb.delete(0,sb.length());
            }
        } catch (InterruptedIOException ie) {
            logger.warn("读取日志输出中断",ie);
            interrupt();
        } catch (Exception e) {
            logger.warn("读取日志输出异常",e);
        }finally {
            try {
                if (adbTransport != null) {
                    adbTransport.close();
                }
                if (bi != null) {
                    bi.close();
                }
                if (fw != null) {
                    fw.close();
                }
            }catch (Exception e) {
                logger.warn("日志线程关闭流异常",e);
            }
        }
        logger.info("[" +serial+ "]日志获取结束，时间:{}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

    //将level转换成对应数字级别
    private String transLevelData(String level) {
        String value = "0";
        if (StringUtils.isNotBlank(level)) {
            switch (level) {
                case "V":
                    value = "2";
                    break;
                case "D":
                    value = "3";
                    break;
                case "I":
                    value = "4";
                    break;
                case "W":
                    value = "5";
                    break;
                case "E":
                    value = "6";
                    break;
                case "F":
                    value = "7";
                    break;
                case "S":
                    value = "8";
                    break;
                default:
                    value = "1";
                    break;
            }
        }
        return value;
    }

    public String stopLog(String tenantId){
        if (null != adbTransport) {
            try {
                alive = false;
                adbTransport.close();
                //上传文件
                logger.info("[" +serial+ "]日志停止，开始上传日志文件");
                String serverAddress = SpringUtils.getProperties("nk.mobile-computer.serverAddr");
                String pubUploadPath = SpringUtils.getProperties("nk.mobile-computer.publicUploadAddr");
                logger.info("开始上传安卓设备日志文件，设备Id：{}", serial);
                Attachment upload = HttpUtils.upload(serverAddress + pubUploadPath, logFilePath, tenantId, null, FileBusinessTypeEnum.MOBILE_TASK_LOG.getCode());
                if (null != upload && StringUtils.isNotBlank(upload.getId())) {
                    logger.debug("日志文件上传成功，返回id：{}，path：{}", upload.getId(), upload.getUrlPath());
                    return upload.getUrlPath();
                }
            } catch (Exception e) {
                logger.error("上传日志异常:",e);
            }
        }
        return null;
    }

    public void killLog(){
        if (null != adbTransport) {
            try {
                alive = false;
                adbTransport.close();
            } catch (IOException e) {
                logger.error("关闭日志会话异常:",e);
            }
        }
    }
}
