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

import net.northking.cctp.upperComputer.constants.ResponseCmd;
import net.northking.cctp.upperComputer.deviceManager.IOSDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.thread.IosDeviceInitThread;
import net.northking.cctp.upperComputer.driver.ios.NKAgent;
import net.northking.cctp.upperComputer.driver.usbmuxd.AppleDevice;
import net.northking.cctp.upperComputer.driver.usbmuxd.UsbMuxd;
import net.northking.cctp.upperComputer.driver.usbmuxd.UsbMuxdConnectFailedException;
import net.northking.cctp.upperComputer.driver.usbmuxd.payload.usbmuxd.entity.DeviceConnectionDetail;
import net.northking.cctp.upperComputer.entity.PhoneEntity;
import net.northking.cctp.upperComputer.utils.SessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.websocket.Session;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author : yineng.huang
 * @date : 2023/10/17 16:41
 */
public class IosScreenResponseThread extends ImageScreenResponse {

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

    private static final int WEB_DRIVER_AGENT_SCREEN_PORT = 9100;
    /**
     * 每个数据块的固定开头
     */
    private static final String BOUNDARY_STRING = "--BoundaryString--Content-type: image/jpg--=";

    /**
     * 最后有效图片头部块
     */
    private final byte[] lastChunkHeader = new byte[BOUNDARY_STRING.length() + 2];

    public static float compressQuality = 0.75f;
    /**
     * 输出header，请求方连接后首先发送，每次连接只发一次
     */
    private String header = null;

    private PhoneEntity phone;

    private long num = 1;

    private UsbMuxd.ConnectOperator connectOperator;

    @Override
    public void run() {
        logger.info("即将开始拉取设备【{}】图片................................", phone.getUdid());
        while (!isInterrupted()) {
            if (!CollectionUtils.isEmpty(webSessions)) {
                //通知前端开始连接
                Map<String, Object> messageMap = new HashMap<>();
                messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTING);
                for (Session webSession : webSessions) {
                    if (webSession.isOpen()) {
                        SessionUtils.sendMessageInitiative(webSession, ResponseCmd.DEVICE_STATUS, phone.getUdid(), messageMap, "设备掉线了");
                    }
                }
            }
            UsbMuxd usbmuxd = new UsbMuxd();
            connectOperator = getDeviceConnectOperator(usbmuxd);
            if (connectOperator == null) {
                logger.warn("未能获取与设备[" + phone.getUdid() + "]的通信操作对象，稍后重试");
                try {
                    sleep(500);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                }
                continue;
            }
            try {
                connectOperator.outputStream.write("\n\n".getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                logger.warn("传递指令到设备[" + phone.getUdid() + "]时发生输入输出错误，稍后重试");
                try {
                    sleep(500);
                } catch (InterruptedException ignored) {
                    interrupt();
                }
                continue;
            }

            byte[] readCache = new byte[4096];
            ByteArrayOutputStream readBuffer = new ByteArrayOutputStream();
            ByteArrayOutputStream chunkBuffer = new ByteArrayOutputStream();
            byte[] chunkHeaderByteArray = BOUNDARY_STRING.getBytes();
            int chunkHeaderPosition = 0;
            int readBufferChunkEndIndex = 0;
            boolean readFirstChunk = false;
            int lastRawChunkSize = 0;
            boolean confirmSameFrame = false;

            int foundChunkHeaderAndNeedMoreBytes = 0;

            try {
                while (!isInterrupted()) {
                    int count = connectOperator.inputStream.read(readCache);
                    if (count == -1) break;
                    if (count == 0) continue;
                    readBuffer.write(readCache, 0, count);

                    int i = 0;

                    while (i < count) {
                        if (foundChunkHeaderAndNeedMoreBytes > 0) {
                            foundChunkHeaderAndNeedMoreBytes--;
                            readBufferChunkEndIndex++;
                            if (foundChunkHeaderAndNeedMoreBytes == 0) {

                                byte[] readArray = readBuffer.toByteArray();

                                chunkBuffer.write(readArray, 0, readBufferChunkEndIndex - 2 - chunkHeaderByteArray.length);

                                readBuffer.reset();
                                int k = readBufferChunkEndIndex - 2 - chunkHeaderByteArray.length;
                                for (int j = 0; j < BOUNDARY_STRING.length() + 2; j++, k++) {
                                    lastChunkHeader[j] = readArray[k];
                                }
                                readBuffer.write(readArray, readBufferChunkEndIndex, readArray.length - readBufferChunkEndIndex);

                                readBufferChunkEndIndex = 0;
                                if (!readFirstChunk) {
                                    readFirstChunk = true;
                                    header = chunkBuffer.toString();
                                    chunkBuffer.reset();
//                                    notifyChunkReady();
                                    i++;
                                    continue;
                                }
                                byte[] rawImageFileByteArray = chunkBuffer.toByteArray();
                                //这里是录屏
                                if (null != screenRecorder) {
                                    screenRecorder.addImgToVideo(rawImageFileByteArray);
                                }
//                                if (compressQuality != 1f) {
//
////                                    chunkHandleThread.putChunk(rawImageFileByteArray);
//                                } else {
////                                    lastChunk = rawImageFileByteArray;
////                                    notifyChunkReady();
//                                }
//                                if (lastRawChunkSize == rawImageFileByteArray.length) {
//                                if (Math.abs(lastRawChunkSize - rawImageFileByteArray.length)<=1000) {
//                                    if (confirmSameFrame) {
//                                        chunkBuffer.reset();
//                                        i++;
//                                        continue;
//                                    }
//                                    confirmSameFrame = true;
//                                } else {
//                                    confirmSameFrame = false;
//                                    lastRawChunkSize = rawImageFileByteArray.length;
//                                }

                                //有后端会话则给后端推送屏幕图片
                                if (!CollectionUtils.isEmpty(webSessions)) {
                                    Iterator<Session> iterator = webSessions.iterator();
                                    while (iterator.hasNext()) {
                                        Session webSession = iterator.next();
                                        if (webSession.isOpen()) {
                                            if (sendDeviceStatus) {
                                                Map<String, Object> result = new HashMap<>();
                                                result.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTED);
                                                SessionUtils.sendMessageInitiative(webSession, ResponseCmd.DEVICE_STATUS, deviceId, result, "设备连接失败");
                                                sendDeviceStatus = false;
                                            }
                                            SessionUtils.sendBinary(webSession, rawImageFileByteArray);
                                        } else {
                                            logger.warn("推送到web端的session已经断开，sessionId:{}",webSession.getId());
                                            iterator.remove();
                                        }
                                    }
                                }
//                                if (null != screenCompressHandle && screenCompressHandle.isAlive() && !screenCompressHandle.isInterrupted()) {
//                                    screenCompressHandle.addData(rawImageFileByteArray);
//                                }
                                chunkBuffer.reset();
                            }
                            i++;
                            continue;
                        }

                        if (chunkHeaderByteArray[chunkHeaderPosition] == readCache[i]) {
                            chunkHeaderPosition++;
                            if (chunkHeaderPosition == chunkHeaderByteArray.length) {
                                foundChunkHeaderAndNeedMoreBytes = 2;
                                readBufferChunkEndIndex++;
                                chunkHeaderPosition = 0;
                                i++;
                                continue;
                            }
                        } else {
                            chunkHeaderPosition = 0;
                        }
                        readBufferChunkEndIndex++;
                        i++;
                    }
                }
            } catch (IOException e) {
                logger.error("从设备读取数据失败，稍后重试", e);
                try {
                    sleep(500);
                } catch (InterruptedException ignored) {
                    interrupt();
                    break;
                }
            }

        }
        logger.warn("设备【{}】抓取屏幕线程退出。。。。。。。。。。。。", phone.getUdid());
    }

    /**
     * @param phone
     */
    public IosScreenResponseThread(PhoneEntity phone) {
//        screenCompressHandle = new IosScreenCompressHandleThread(phone.getUdid());
//        screenCompressHandle.start();
        this.phone = phone;
        this.deviceId = phone.getUdid();
        setName(phone.getUdid() + "拉取屏幕");
    }

    private UsbMuxd.ConnectOperator getDeviceConnectOperator(UsbMuxd usbMuxd) {
        try {
            List<DeviceConnectionDetail> connectionDetailList = usbMuxd.listDevices();
            for (DeviceConnectionDetail detail : connectionDetailList) {
                if (detail.serialNumber.equalsIgnoreCase(phone.getUdid()) && detail.connectStatus == DeviceConnectionDetail.ConnectStatus.ATTACHED) {
                    AppleDevice appleDevice = new AppleDevice(detail);
                    try {
                        return usbMuxd.connectDeviceLocalPort(appleDevice, WEB_DRIVER_AGENT_SCREEN_PORT);
                    } catch (IOException e) {
                        logger.warn("设备已连接，但无法连接WebDriverAgent端口:" + WEB_DRIVER_AGENT_SCREEN_PORT);
                    }
                }
            }
        } catch (UsbMuxdConnectFailedException e) {
            logger.error("查找设备时无法连接到usbmuxd，是否至少连接了一个苹果设备？", e);
        } catch (IOException e) {
            logger.error("查找设备时与usbmuxd通信发生错误", e);
        }
        return null;
    }

    public void changeSize(int width, int height) {
//        if (this.screenCompressHandle != null && this.screenCompressHandle.isAlive() && !this.screenCompressHandle.isInterrupted()) {
//            this.screenCompressHandle.setScreenSize(width,height);
//        } else {
//            logger.warn("手机【】的图像传输线程未准备好。。。。。。。。。。。。",phone.getUdid());
//        }
    }

    public void changeQuality(float quality,int frameRate) {
        IosDeviceInitThread iosInitThread = IOSDeviceManager.getInstance().getIosInitThread(phone.getUdid());
        if (null != iosInitThread && !iosInitThread.isInterrupted() && iosInitThread.isAlive()) {
            logger.warn("设置手机【{}】推送图片的帧率：{}",phone.getUdid(),frameRate);
            iosInitThread.setMJPEGServerRate(frameRate);
        } else {
            logger.warn("设备【{}】已经不在线了............................");
        }
    }

    public void stopFetchPic() {
        logger.warn("设备【{}】即将退出屏幕的抓取。。。。。。", phone.getUdid());
        if (null != connectOperator) {
            try {
                connectOperator.close();
            } catch (Exception e) {
                logger.warn("设备【{}】关闭图像抓取失败。。。。。", phone.getUdid(), e);
            }
        }
        //发送消息通知wda停止获取图片
        IosDeviceInitThread iosInitThread = IOSDeviceManager.getInstance().getIosInitThread(phone.getUdid());
        if (null != iosInitThread && !iosInitThread.isInterrupted() && iosInitThread.isAlive()) {
            NKAgent nkAgent = iosInitThread.getNkAgent();
            boolean success = nkAgent.disconnectAllMJpegSever();
            logger.info("通知wda取消推图的结果：{}",success);
        }
        IOSDeviceManager.getInstance().removeScreenThread(phone.getUdid());
        interrupt();
    }

    @Override
    public void changeScreenSize() {

    }


}
