package net.northking.cctp.upperComputer.driver.agent;


import cn.hutool.core.util.StrUtil;
import net.northking.cctp.upperComputer.driver.adb.Adb;
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
import net.northking.cctp.upperComputer.driver.adb.AdbTransport;
import net.northking.cctp.upperComputer.driver.agent.command.CloseSessionCommand;
import net.northking.cctp.upperComputer.driver.agent.command.StopCommand;
import net.northking.cctp.upperComputer.driver.agent.command.protocol.ProtocolCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 与Android上运行的Agent的通信会话
 */
public class AndroidAgentSession {

    private Logger logger = LoggerFactory.getLogger(AndroidAgentSession.class);
    /**
     * 当前代码对接agent程序的接口版本
     */
    public static final int API_VERSION = 1;

    /**
     * 是否异步模式
     */
    final boolean isAsync;

    /**
     * 设备序列号(id)
     */
    final String serial;

    private ArrayBlockingQueue<ProtocolCommand> sendQueue;

    private CommandSendThread sendThread;

    private AdbTransport transport;

    private DataInputStream dataInputStream;

    private DataOutputStream dataOutputStream;

    private boolean state;

    public  boolean isState() {
        return  state;
    }

    public AndroidAgentSession(AdbDevice adbDevice, boolean isAsync) {
        this.isAsync = isAsync;
        if (isAsync) {
            sendQueue = new ArrayBlockingQueue<>(20);
            sendThread = new CommandSendThread();
        }
        this.serial = adbDevice.getSerial();
    }

    public void start() throws IOException {
        Adb adb = new Adb();
        AdbDevice adbDevice = null;
        for (AdbDevice currentDevice : adb.listDevices()) {
            if (serial.equals(currentDevice.getSerial())) {
                logger.debug("已有设备创建会话 serial："+serial);
                adbDevice = currentDevice;
                break;
            }
        }
        if (adbDevice == null) {
            throw new IllegalStateException("未找到指定的设备[" + serial + "]，确定已经连接？");
        }
        if (adbDevice.state != AdbDevice.State.Device) {
            throw new IllegalStateException("设备[" + serial + "]处于非可用状态" + adbDevice.state);
        }

        transport = adb.shell(adbDevice, "export CLASSPATH=/data/local/tmp/agent.apk;app_process /system/bin net.northking.product.cctpplus.SocketHelper unix-domain agent");
        dataInputStream = new DataInputStream(transport.getInputStream());
        dataOutputStream = new DataOutputStream(transport.getOutputStream());
        state = true;
        if (isAsync) {
            //todo 改用ThreadScope
            sendThread.start();
        }
    }

    /**
     * 发送指令
     *
     * @param command 指令
     * @return 返回数据结果，如果会话为异步模式，则始终为null
     */
    @SuppressWarnings("unchecked")
    public <T> T send(ProtocolCommand<T> command) {
        if (isAsync) {
            try {
                sendQueue.put(command);
            } catch (InterruptedException ignore) {

            }
            return null;
        } else {
            try {
                dataOutputStream.writeInt(command.getCommandId());
                command.doSend(dataOutputStream);
                if (command == CloseSessionCommand.getInstance()) {
                    closeSilence();
                    return null;
                }
            } catch (IOException e) {
                logger.error("发送指令出现错误：{}",e);
            }
            try {
                int returnCommandId = dataInputStream.readInt();
                logger.debug("===returnCommandId："+returnCommandId);
                if (returnCommandId != command.getCommandId()) {
                    System.out.println("commandId [" + returnCommandId + "] not match [" + command.getCommandId() + "]");
                    return null;
                }
                return (T) command.buildReceive(dataInputStream);
            } catch (Exception e) {
                state = false;
                logger.debug("处理指令:"+command.getCommandId()+"时发生错误:{}",e);
                return null;
            }
        }
    }

    public DataInput getDataInput() {
        return dataInputStream;
    }

    /**
     * 安静地关闭流
     */
    public void closeSilence() {
        if (null != this.sendThread) {
            this.sendThread.setRunning(false);
            this.sendQueue.clear();
            StopCommand sc = new StopCommand();
            this.sendQueue.add(sc);   // 添加结束命令command
            try {
                this.sendThread.join();
            } catch (InterruptedException e) {
                logger.error("线程join失败", e);
            }
        }
        state = false;
    }

    private class CommandSendThread extends Thread {
        private volatile boolean running = true;

        public void setRunning(boolean running) {
            this.running = running;
        }
        @Override
        public void run() {
            while (running) {
                ProtocolCommand command;
                try {
                    command = sendQueue.take();
                    logger.debug("获取到指令信息：{}", StrUtil.toString(command));
                } catch (InterruptedException e) {
                    break;
                }

                try {
                    if (command.getCommandId() != -999) {
                        dataOutputStream.writeInt(command.getCommandId());
                        command.doSend(dataOutputStream);
                    } else {
                        logger.debug("线程准备停止....");
                    }
                } catch (IOException ignore) {
                    break;
                }
            }
            try {
                logger.debug("关闭设备【{}】的agentSession连接",serial);
                if (transport != null) {
                    transport.close();
                }
            } catch (IOException ignore) {

            }
        }
    }
}
