package net.northking.cctp.upperComputer.deviceManager;

import cn.hutool.extra.spring.SpringUtil;
import net.northking.cctp.upperComputer.constants.UpperComputerConstant;
import net.northking.cctp.upperComputer.deviceManager.thread.AppiumEnvironmentThread;
import net.northking.cctp.upperComputer.deviceManager.thread.UpperComputerHeartThread;
import net.northking.cctp.upperComputer.deviceManager.thread.UsbMuxdDriverThread;
import net.northking.cctp.upperComputer.entity.CdDeviceCtrl;
import net.northking.cctp.upperComputer.entity.ComputerHeartInfo;
import net.northking.cctp.upperComputer.exception.ExecuteException;
import net.northking.cctp.upperComputer.listener.UpperComputerConsumer;
import net.northking.cctp.upperComputer.utils.HttpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.http.HttpEntity;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

public class UpperComputerManager {

    private static UpperComputerManager upperComputerManager;

    private static final Logger logger = LoggerFactory.getLogger(UpperComputerManager.class);

    private String computerId;   //上位机id

    private String applicationPath;  //上位机程序所在目录

    private String host;  //上位机ip地址

    private int port;   //上位机端口

    private String appiumPort;  //appium端口

    private String operatingSystem;  //操作系统

    private UpperComputerHeartThread upperComputerHeartThread;

    private ComputerHeartInfo computerHeartInfo;

    private AppiumEnvironmentThread appiumEnvironmentThread;

    private UsbMuxdDriverThread usbMuxdDriverThread;

    public static UpperComputerManager getInstance() {
        if (upperComputerManager == null) {
            upperComputerManager = new UpperComputerManager();
        }
        return upperComputerManager;
    }

    public ComputerHeartInfo getComputerHeartInfo() {
        List<String> onlineDeviceIds = new ArrayList<>();
        //android
        List<String> onlineAndroidDeviceIds = AndroidDeviceManager.getInstance().getOnlineDevice();
        //ios
        List<String> onlineIosDeviceIds = IOSDeviceManager.getInstance().getOnlineDevice();
        onlineDeviceIds.addAll(onlineAndroidDeviceIds);
        onlineDeviceIds.addAll(onlineIosDeviceIds);
        this.computerHeartInfo.setDeviceIds(onlineDeviceIds);
        return this.computerHeartInfo;
    }

    public void setComputerHeartInfo(ComputerHeartInfo computerHeartInfo) {
        this.computerHeartInfo = computerHeartInfo;
    }

    public void setComputerId(String computerId) {
        this.computerId = computerId;
    }

    public String getApplicationPath() {
        return applicationPath;
    }

    public void setApplicationPath(String applicationPath) {
        this.applicationPath = applicationPath;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getAppiumPort() {
        return appiumPort;
    }

    public void setAppiumPort(String appiumPort) {
        this.appiumPort = appiumPort;
    }

    /**
     * 初始化上位机参数
     */
    public void initUpperComputerParam() {
        String host = SpringUtil.getProperty("nk.mobile-computer.address");
        if (!StringUtils.hasText(host)) {
            logger.error("请配置上位机的ip地址。。。。");
            System.exit(1);
        }
        String path = System.getProperty("user.dir");
        this.setHost(host);
        this.setApplicationPath(path);
        if (this.port <= 0) {
            logger.error("未获取到上位机启动端口。。");
            System.exit(1);
        }
        String computerId = getComputerId();
        this.setComputerId(computerId);
        //启动appium
        boolean auto = Boolean.parseBoolean(SpringUtil.getProperty("nk.mobile-computer.autoEnvironment"));
        if (auto) {  //自动化环境
            if (!operatingSystem.startsWith("Mac")) {
                String appiumPort = (null == SpringUtil.getProperty("nk.mobile-computer.appium.port") ? "4723" : SpringUtil.getProperty("nk.mobile-computer.appium.port"));
                String appiumPath = SpringUtil.getProperty("nk.mobile-computer.appium.path");
                if (!StringUtils.hasText(appiumPath)) {
                    logger.error("请配置appium所在路径。。。。。");
                    System.exit(1);
                }
                appiumEnvironmentThread = new AppiumEnvironmentThread(appiumPath, appiumPort);
                appiumEnvironmentThread.start();
                this.setAppiumPort(appiumPort);
            }
        }
//        if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Linux")) {
//            usbMuxdDriverThread = new UsbMuxdDriverThread();
//            usbMuxdDriverThread.start();
//        }
        logger.info("初始化上位机参数成功======>host:{},path:{},port:{},computerId:{}",host,path,this.port,computerId);
        ComputerHeartInfo computerHeartInfo = new ComputerHeartInfo();
        computerHeartInfo.setId(computerId);
        computerHeartInfo.setStatus("2");
        computerHeartInfo.setStfAddress(host);
        this.setComputerHeartInfo(computerHeartInfo);
    }

    /**
     * 获取上位id
     * @return
     */
    public static String getComputerId(){
        if (upperComputerManager.computerId != null) {
            return upperComputerManager.computerId;
        }
        logger.info("上位机id文件路径：{}",upperComputerManager.getApplicationPath());
        File idFile = new File(upperComputerManager.getApplicationPath() + "/id.txt");
        FileOutputStream fs = null;
        InputStreamReader in = null;
        BufferedReader br = null;
        try {
            //文件为空
            if(!idFile.exists()){
                logger.info("上位机id文件不存在，开始创建上位机文件");
                boolean newFile = idFile.createNewFile();
                if (!newFile) {
                    logger.warn("创建上位机id文件失败。。。。");
                    throw new ExecuteException("创建上位机id文件失败！！");
                }
                String computerId= UUID.randomUUID().toString().replace("-","");
                fs = new FileOutputStream(idFile);
                fs.write(computerId.getBytes(StandardCharsets.UTF_8));
                //清空缓冲区、关闭流
                fs.flush();
                fs.close();
                logger.info("上位机id文件创建完成");
                return computerId;
            }else {
                logger.info("上位机id文件存在，开始读取上位机id");
                String s = "";
                in = new InputStreamReader(new FileInputStream(idFile),"UTF-8");
                br = new BufferedReader(in);
                StringBuffer content = new StringBuffer();
                while ((s=br.readLine())!=null){
                    content.append(s);
                }
                logger.info("上位机id读取完成");
                return content.toString();
            }
        } catch (Exception e) {
            logger.error("操作上位机id文件失败",e);
            System.exit(1);
            return null;
        }finally {
            if (null != fs) {
                try {
                    fs.close();
                } catch (IOException e) {
                    logger.warn("关闭流报错",e);
                }
            }
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.warn("关闭流报错",e);
                }
            }
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.warn("关闭流报错",e);
                }
            }
        }
    }

    /**
     * 注册上位机
     */
    public static void register() {
        CdDeviceCtrl ctrl = new CdDeviceCtrl();
        ctrl.setId(getComputerId());
        ctrl.setCtrlUpLimit(Integer.valueOf(SpringUtil.getProperty("nk.mobile-computer.ctrlUpLimit")));
        ctrl.setCtrlIp(upperComputerManager.getHost());
        ctrl.setCtrlPort(upperComputerManager.getPort()+"");
        ctrl.setAppiumPort(upperComputerManager.getAppiumPort());
        String result = null;
        try {
            //注册
            URI uri = new URI(SpringUtil.getProperty("nk.mobile-computer.serverAddr") + SpringUtil.getProperty("nk.mobile-computer.ctrlRegisterAddr"));
            HttpEntity<CdDeviceCtrl> entity = new HttpEntity<>(ctrl);
            result = HttpUtils.doPost(uri, entity, String.class);
            logger.debug("注册结果：{}",result);
        }catch (Exception e){
            logger.error("注册上位机请求失败",e);
            System.exit(1);
        }
    }

    /**
     * 注册上位机专属队列
     */
    public static void registerQueue() {
        String queues = UpperComputerConstant.EXCHANGE_UPPER_COMPUTER_QUEUE + "." + getComputerId();
        Queue queue = new Queue(queues,true,false,false);
        RabbitAdmin rabbitAdmin = SpringUtil.getBean(RabbitAdmin.class);
        Exchange exchangeExchange = SpringUtil.getBean("exchangeExchange", Exchange.class);
        SimpleMessageListenerContainer fixedListenerContainer = SpringUtil.getBean("fixedListenerContainer", SimpleMessageListenerContainer.class);
        UpperComputerConsumer upperComputerConsumer = SpringUtil.getBean("upperComputerConsumer", UpperComputerConsumer.class);
        //检查队列是否存在
        Properties properties = rabbitAdmin.getQueueProperties(queues);
        if (null != properties) {
            String consumerCount = properties.get("QUEUE_CONSUMER_COUNT").toString();
            logger.info("存在队列，队列消费者个数为：{}", consumerCount);
            if (StringUtils.hasText(consumerCount) && "0".equals(consumerCount)) {
                logger.info("消费者的个数为0，重新绑定队列交换机和消费者....");
                rabbitAdmin.deleteQueue(queues);
                rabbitAdmin.declareQueue(queue);
                rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchangeExchange).with(getComputerId()).noargs());
                fixedListenerContainer.addQueueNames(queues);
                fixedListenerContainer.setMessageListener(upperComputerConsumer);
            }
        } else {
            logger.info("不存在队列，开始创建..........");
            rabbitAdmin.declareQueue(queue);
            rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(exchangeExchange).with(getComputerId()).noargs());
            fixedListenerContainer.addQueueNames(queues);
            fixedListenerContainer.setMessageListener(upperComputerConsumer);
        }
        logger.info("添加队列，绑定队列和交换机，队列和消费者完成。。。。。。。。。。。，队列名：{}", queue.getName());
    }

    public static void sendHeartToServer(){
        upperComputerManager.upperComputerHeartThread = new UpperComputerHeartThread();
        upperComputerManager.upperComputerHeartThread.start();
    }

    public String getOperatingSystem() {
        return operatingSystem;
    }

    public void setOperatingSystem(String operatingSystem) {
        this.operatingSystem = operatingSystem;
    }

    public static void shutdown(){
        if (null != upperComputerManager.upperComputerHeartThread) {
            upperComputerManager.upperComputerHeartThread.kill();
        }
        if (null != upperComputerManager.appiumEnvironmentThread) {
            upperComputerManager.appiumEnvironmentThread.exitAppium();
        }
        if (null != upperComputerManager.usbMuxdDriverThread) {
            upperComputerManager.usbMuxdDriverThread.exitUsbMuxd();
        }
    }

    public boolean isMac() {
        return operatingSystem.startsWith("Mac");
    }
}
