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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.northking.cctp.upperComputer.deviceManager.IOSDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.UpperComputerManager;
import net.northking.cctp.upperComputer.driver.usbmuxd.AppleDevice;
import net.northking.cctp.upperComputer.entity.PhoneEntity;
import net.northking.cctp.upperComputer.exception.ExecuteException;
import net.northking.cctp.upperComputer.utils.HttpUtils;
import net.northking.cctp.upperComputer.webSocket.function.IosFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author : yineng.huang
 * @date : 2023/10/16 14:42
 */
public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
    private final static Logger logger = LoggerFactory.getLogger(WindowsAndLinuxIosDeviceInitThread.class);

    private final String SUCCESS_FLAG = "WebDriverAgent start successfully";

    private Device8100WatchThread apiProxyThread;

    public WindowsAndLinuxIosDeviceInitThread(PhoneEntity phone, AppleDevice device) {
        super(phone,device);
    }

    @Override
    public void run() {
        logger.debug("不是mac作为上位机，用tidevice启动wda");
        List<String> getPackageCmds = new ArrayList<>();
        getPackageCmds.add("tidevice");
        getPackageCmds.add("-u");
        getPackageCmds.add(phone.getUdid());
        getPackageCmds.add("applist");
        ProcessBuilder builder = new ProcessBuilder(getPackageCmds).redirectErrorStream(true);
        String appPackage = null;
        BufferedReader reader = null;
        try {
            Process process = builder.start();
            if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Windows")) {
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));
            } else if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Linux")) {
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            }
            String line = null;
            while ((line = reader.readLine()) != null) {
                logger.debug("得到应用：{}", line);
                if (line.contains("WebDriverAgentRunner-Runner 1.0")) {
                    String[] split = line.split(" ");
                    appPackage = split[0];
                    break;
                }
            }
        } catch (IOException e) {
            logger.error("获取包名失败", e);
        }
        logger.debug("得到包名：{}", appPackage);
        if (!StringUtils.hasText(appPackage)) {
            throw new ExecuteException(String.format("未获取到手机[%s]的WDA包名，无法启动WDA", phone.getUdid()));
        }
        List<String> cmds = new ArrayList<>();
        cmds.add("tidevice");
        cmds.add("-u");
        cmds.add(phone.getUdid());
        cmds.add("xctest");
        cmds.add("-B");
        cmds.add(appPackage);
        cmds.add("--debug");
        ProcessBuilder processBuilder = new ProcessBuilder().command(cmds);
        processBuilder.redirectErrorStream(true);
        LineNumberReader input = null;
        File wdaLogPath = new File(UpperComputerManager.getInstance().getApplicationPath() + "/wdaLog");
        if (!wdaLogPath.exists()) {
            wdaLogPath.mkdirs();
        }
        while (!isInterrupted()) {
            File wdaLogFile = new File(wdaLogPath.getAbsolutePath() + "/WDA-" + appleDevice.getConnectionDetail().serialNumber + "-" + getLogFileNameDateTime() + ".log");
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(wdaLogFile);
                this.process = processBuilder.start();
                if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Windows")) {
                    input = new LineNumberReader(new InputStreamReader(this.process.getInputStream(),"GBK"));
                } else if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Linux")) {
                    input = new LineNumberReader(new InputStreamReader(this.process.getInputStream(),"UTF-8"));
                }
                String line = null;
                while (null != (line = input.readLine())) {
                    if (line.contains("NKLog:")) {
                        fileOutputStream.write(line.getBytes(StandardCharsets.UTF_8));
                        fileOutputStream.write(10);
                    }
                    if (line.contains(SUCCESS_FLAG)) {
                        logger.info("设备【{}】的wda程序启动成功，开启nkAgent。。。。。。。。。", phone.getUdid());
                        isFBServerReady = true;
                        createNKAgent("非macOS启动wda第一创建NKAgent");
                        logger.info("设备【{}】即将启动8100端口代理。。。。。。。。。", phone.getUdid());
                        apiProxyThread = new Device8100WatchThread(phone);
                        apiProxyThread.start();
                    }
                }
            } catch (IOException e) {
                logger.error("启动wda程序出错", e);
            }finally {
                if (null != fileOutputStream) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            int code = 0;
            try {
                code = this.process.waitFor();
            } catch (InterruptedException e) {
                logger.warn("wda线程中断了。。。。");
                interrupt();
            }
            phone.setStatus(false);
            logger.warn("设备【{}】的wda程序死求。。。,退出码：{}", phone.getUdid(), code);
            if (apiProxyThread != null && !apiProxyThread.isInterrupted() && apiProxyThread.isAlive()) {
                apiProxyThread.exit8100Process();
            }
            IOSDeviceManager.getInstance().publishDeviceAgentDead(phone.getUdid());
        }
    }


    public void apiPortReady() {
        new Thread(() -> {
            logger.debug("获取设备【{}】的屏幕比。。。。。。。", phone.getUdid());
            JSONObject object = null;
            try {
                object = HttpUtils.doGet(new URI("http://localhost:" + phone.getPort8100() + "/window/size"), JSONObject.class);
            } catch (URISyntaxException uriSyntaxException) {
                logger.warn("设备【{}】请求屏幕数据时url不对", phone.getUdid());
                return;
            } catch (Exception e) {
                logger.warn("设备【{}】请求屏幕数据时出错，待会再试", phone.getUdid());
                return;
            }
            JSONObject value = object.getJSONObject("value");
            int width = value.getInteger("width");
            int height = value.getInteger("height");
            int scale = value.getIntValue("scale");
            logger.info("手机【{}】的宽:{}高:{},缩放比：{}", phone.getUdid(), width, height, scale);
            phone.setScreenWidth(width);
            phone.setScreenHeight(height);
            phone.setScale(scale);
            logger.warn("注册设备【{}】。。。", phone.getUdid());
            try {
                deviceInfo = getDeviceInfo();
            } catch (IOException e) {
                logger.error("获取设备信息失败", e);
                return;
            }
            logger.debug("注册设备信息：{}", JSON.toJSONString(deviceInfo));
            IOSDeviceManager.getInstance().registerDeviceToDeviceManager(deviceInfo);
            phone.setStatus(true);
            //创建访问session
            JSONObject sessionObject = null;
            try {
                Map<String, Object> paramMap = new HashMap<>();
                Map<String, Boolean> capabilities = new HashMap<>();
                capabilities.put("shouldUseTestManagerForVisibilityDetection", false);
                capabilities.put("shouldUseCompactResponses", false);
                paramMap.put("capabilities", capabilities);
                HttpEntity<Map<String, Object>> entity = new HttpEntity<>(paramMap, null);
                sessionObject = HttpUtils.doPost(new URI("http://localhost:" + phone.getPort8100() + "/session"), entity, JSONObject.class);
                JSONObject valueMap = sessionObject.getJSONObject("value");
                if (null != valueMap) {
                    String sessionId = valueMap.getString("sessionId");
                    logger.info("设备【{}】得wdaSessionId为：{}", phone.getUdid(), sessionId);
                    IOSDeviceManager.getInstance().addPhoneSessionId(phone.getUdid(), sessionId);
                }
            } catch (URISyntaxException uriSyntaxException) {
                logger.warn("设备【{}】请求创建session时url不对", phone.getUdid());
                return;
            } catch (Exception e) {
                logger.warn("设备【{}】请求创建session时出错，待会再试", phone.getUdid());
                return;
            }
            IOSDeviceManager.getInstance().publishDeviceAgentAlready(phone.getUdid());
        }).start();
    }

    public LinkedHashMap<String, Object> getDeviceInfo() throws IOException {
        LinkedHashMap<String, Object> deviceInfo = new LinkedHashMap<>();
        ProcessBuilder builderSimple = new ProcessBuilder();
        String[] cmdsSimple = {"tidevice", "-u", phone.getUdid(), "info"};
        Process simpleProcess = builderSimple.command(Arrays.asList(cmdsSimple)).redirectErrorStream(true).start();
        LineNumberReader simpleNumberReader = new LineNumberReader(new InputStreamReader(simpleProcess.getInputStream()));
        Map<String, String> deviceProperties = new HashMap<String, String>();
        String line = null;
        while ((line = simpleNumberReader.readLine()) != null) {
            String[] split = line.split(":");
            if (split.length == 2) {
                String key = split[0].trim();
                String value = split[1].trim();
                deviceProperties.put(key, value);
            }
        }
        ProcessBuilder builderDetail = new ProcessBuilder();
        String[] cmdsDetail = {"tidevice", "-u", phone.getUdid(), "info", "--json"};
        Process infoDetailProcess = builderDetail.command(Arrays.asList(cmdsDetail)).redirectErrorStream(true).start();
        LineNumberReader detailNumberReader = new LineNumberReader(new InputStreamReader(infoDetailProcess.getInputStream()));
        StringBuilder infoMessage = new StringBuilder();
        while (null != (line = detailNumberReader.readLine())) {
            infoMessage.append(line);
        }
        JSONObject info = JSONObject.parseObject(infoMessage.toString(), JSONObject.class);
        //region 平台
        deviceInfo.put("platform", "ios");
        //region 品牌
        deviceInfo.put("manufacturer", info.getOrDefault("DeviceClass", "unknown"));
        //region 型号
        deviceInfo.put("model", deviceProperties.getOrDefault("MarketName", "unknown"));
        //region 产品
        deviceInfo.put("product", deviceProperties.getOrDefault("ProductName", "unknown"));
        //region 设备号
        deviceInfo.put("serial", phone.getUdid());
        //region 平台版本
        deviceInfo.put("version", deviceProperties.getOrDefault("ProductVersion", "unknown"));
        //屏幕尺寸
        IosFunction function = new IosFunction(phone.getPort8100());
        JSONObject screenSize = function.getScreenSize();
        Integer scale = screenSize.getIntValue("scale");
        Integer width = screenSize.getIntValue("width");
        Integer height = screenSize.getIntValue("height");
        deviceInfo.put("width", width * scale);
        deviceInfo.put("height", height * scale);
        deviceInfo.put("scale", scale.doubleValue());

        deviceInfo.put("isHarmony", false);
        deviceInfo.put("wdaUrl", "http://" + UpperComputerManager.getInstance().getHost() + ":" + phone.getPort8100());
        JSONObject rotation = function.getScreenRotation();
        int z = rotation.getIntValue("z");
        deviceInfo.put("rotation", z / 90);
        return deviceInfo;
    }

    public void exitWdaAndProxy() {
        this.process.destroy();
        interrupt();
    }


}
