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

import com.alibaba.fastjson.JSON;
import net.northking.cctp.upperComputer.constants.ResponseCmd;
import net.northking.cctp.upperComputer.deviceManager.AndroidDeviceManager;
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
import net.northking.cctp.upperComputer.driver.agent.AndroidAgentSession;
import net.northking.cctp.upperComputer.driver.agent.command.MediaCodecListCommand;
import net.northking.cctp.upperComputer.driver.agent.command.StartScreenVideoCommand;
import net.northking.cctp.upperComputer.driver.agent.command.StopScreenVideoCommand;
import net.northking.cctp.upperComputer.driver.agent.command.WatchScreenVideoFrameCommand;
import net.northking.cctp.upperComputer.driver.agent.command.data.MediaCodecInfo;
import net.northking.cctp.upperComputer.driver.agent.command.data.ScreenVideoFrame;
import net.northking.cctp.upperComputer.utils.SessionUtils;
import net.northking.cctp.upperComputer.webSocket.entity.CatchParam;
import net.northking.cctp.upperComputer.webSocket.entity.CmdRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.websocket.Session;
import java.io.DataInput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AndroidVideoScreenResponseThread extends Thread {

    private AndroidAgentSession asyncAgentSession;

    private Session wsSession;

    private AdbDevice adbDevice;

    private CmdRequest screenOnRequest;

    private CatchParam catchParam;

    private byte[] lastData;

    private boolean isNewConnect = true;

    private StartScreenVideoCommand startScreenVideoCommand;

    private String videoEncoder = null;

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

    public AndroidVideoScreenResponseThread(Session wsSession, AdbDevice adbDevice, CatchParam catchParam) {
        this.wsSession = wsSession;
        this.adbDevice = adbDevice;
        this.catchParam = catchParam;
        setName("[" + adbDevice.getSerial() + "-response]");
    }

    public void setScreenOnRequest(CmdRequest screenOnRequest) {
        this.screenOnRequest = screenOnRequest;
    }

    @Override
    public void run() {
        while (!isInterrupted()) {
            //通知前端开始连接
            Map<String, Object> messageMap = new HashMap<>();
            messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTING);
            SessionUtils.sendMessageInitiative(wsSession, ResponseCmd.DEVICE_STATUS, adbDevice.getSerial(), messageMap, "设备开始连接");
            AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(adbDevice.getSerial());
            if (null == currentDevice) {
                logger.warn("设备【{}】掉线了，等待设备准备好再打开视频流........", adbDevice.getSerial());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    break;
                }
                continue;
            } else {
                logger.warn("设备【{}】没掉线，继续........", adbDevice.getSerial());
            }
            logger.info("开启设备【{}】视频流屏幕监听。。。。。。。。。。", adbDevice.getSerial());
            this.asyncAgentSession = new AndroidAgentSession(adbDevice, true);
            if (StringUtils.hasText(videoEncoder)) {
                logger.debug("设备【{}】已经有视频流的编码:{},无需查询...............", adbDevice.getSerial(),videoEncoder);
            } else {
                AndroidAgentSession agentSession = null;
                try {
                    agentSession = new AndroidAgentSession(adbDevice, false);
                    agentSession.start();
                    ArrayList<MediaCodecInfo> mediaCodecInfos = agentSession.send(MediaCodecListCommand.getInstance());
                    if (CollectionUtils.isEmpty(mediaCodecInfos)) {
                        SessionUtils.sendFailureMessage(wsSession, screenOnRequest, "此设备不支持视频流，请选择图片流的方式");
                        break;
                    }
                    for (MediaCodecInfo mediaCodecInfo : mediaCodecInfos) {
                        if (mediaCodecInfo.isEncoder()) {  //是编码器
                            List<String> supportedTypes = mediaCodecInfo.getSupportedTypes();
                            if (!CollectionUtils.isEmpty(supportedTypes)) {
                                for (String type : supportedTypes) {
                                    if ("video/avc".equals(type)) {
                                        videoEncoder = mediaCodecInfo.getName();
                                        break;
                                    }
                                }
                            }
                            if (StringUtils.hasText(videoEncoder)) {
                                logger.info("视频流编码：{}", videoEncoder);
                                break;
                            }
                        }
                    }
                    if (!StringUtils.hasText(videoEncoder)) {
                        SessionUtils.sendFailureMessage(wsSession, screenOnRequest, "未找到合适的视频编码器");
                        break;
                    }
                } catch (IOException e) {
                    logger.warn("无法与设备【{}】的agent通信",adbDevice.getSerial());
                    SessionUtils.sendFailureMessage(wsSession, screenOnRequest, "无法创建设备连接,请稍后再试");
                }finally {
                    if (null != agentSession) {
                        agentSession.closeSilence();
                    }
                }
            }
            try {
                this.asyncAgentSession.start();
                logger.debug("开启屏幕=====>width：{} height:{} quality:{} frameRate:{},rotation:{}", catchParam.getWidth(), catchParam.getHeight(), catchParam.getQuality(), catchParam.getFrameRate(), catchParam.getRotation());
                startScreenVideoCommand = StartScreenVideoCommand.getInstance();
                startScreenVideoCommand.setDisplay(catchParam.getDisplay());
                startScreenVideoCommand.setEncoderName(videoEncoder);
                startScreenVideoCommand.setFrameRate(60);
                startScreenVideoCommand.setMaxFps(0);
                startScreenVideoCommand.setiFrameInterval(1);
                startScreenVideoCommand.setWidth(catchParam.getVideoWidth());
                startScreenVideoCommand.setHeight(catchParam.getVideoHeight());
                int quality = catchParam.getQuality();
                setVideoQuality(quality);
                this.asyncAgentSession.send(WatchScreenVideoFrameCommand.getInstance());
                logger.debug("发送command参数：{}", JSON.toJSONString(startScreenVideoCommand));
                this.asyncAgentSession.send(startScreenVideoCommand);
            } catch (IOException e) {
                logger.error("创建agentSession出错。。。。。。", e);
                interrupt();
                messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.DISCONNECT);
                messageMap.put(ResponseCmd.DeviceStatus.MESSAGE, "设备掉线");
                SessionUtils.sendMessageInitiative(wsSession, ResponseCmd.DEVICE_STATUS, adbDevice.getSerial(), messageMap, "设备掉线了");
                this.asyncAgentSession.closeSilence();
                break;
            }
//            sendConnectInfo2Web();
            DataInput dataInput = asyncAgentSession.getDataInput();
            logger.debug("开始读取视频流的数据.............................................");
            int num = 1;
            while (!isInterrupted()) {
                try {
                    int commandId = dataInput.readInt();
                    logger.debug("读取到commandId:{}",commandId);
                    if (commandId == WatchScreenVideoFrameCommand.getInstance().getCommandId()) {//视频流
                        ScreenVideoFrame frame = WatchScreenVideoFrameCommand.getInstance().buildReceive(dataInput);
                        byte[] data = frame.data;
                        ByteBuffer byteBuffer = ByteBuffer.allocate(12 + data.length);
                        byteBuffer.putLong(frame.presentationTimeUs);
                        byteBuffer.putInt(frame.flags);
                        byteBuffer.put(data);
                        SessionUtils.sendBinary(wsSession, byteBuffer.array());
                        logger.debug("发送到前端：{}帧",num++);
                    } else if (commandId == StartScreenVideoCommand.getInstance().getCommandId()) {
                        StartScreenVideoCommand.Result result = StartScreenVideoCommand.getInstance().buildReceive(dataInput);
                        if (result.configCode != 0) {
                            logger.warn("启动串流参数错误，错误码：" + result.configCode);
                        }
                        messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTED);
                        SessionUtils.sendMessageInitiative(wsSession, ResponseCmd.DEVICE_STATUS, adbDevice.getSerial(), messageMap, "设备掉线了");
                        Map<String, Object> resultMap = new HashMap<>();
                        resultMap.put("code", result.configCode);
                        resultMap.put("cacheFrameCount", result.cacheFrames.size());
                        SessionUtils.sendSuccessData(wsSession, screenOnRequest, resultMap, "视频流开启成功");
                        for (ScreenVideoFrame frame : result.cacheFrames) {
                            ByteBuffer byteBuffer = ByteBuffer.allocate(12 + frame.data.length);
                            byteBuffer.putLong(frame.presentationTimeUs);
                            byteBuffer.putInt(frame.flags);
                            byteBuffer.put(frame.data);
                            SessionUtils.sendBinary(wsSession, byteBuffer.array());
                            logger.debug("发送到前端：{}帧",num++);
                        }
//                        result.cacheFrames.forEach((frame) -> {
//                            ByteBuffer byteBuffer = ByteBuffer.allocate(12 + frame.data.length);
//                            byteBuffer.putLong(frame.presentationTimeUs);
//                            byteBuffer.putInt(frame.flags);
//                            byteBuffer.put(frame.data);
//                            SessionUtils.sendBinary(wsSession, byteBuffer.array());
//                        });
                    }
                } catch (IOException e) {
                    logger.warn("读取agentSession输出出错", e);
                    break;
                }
            }
            logger.warn("重新建立设备【{}】的视频流。。。。。。。。。。。。",adbDevice.getSerial());
            this.asyncAgentSession.closeSilence();
        }
        logger.warn("响应设备【{}】的屏幕到上位机的线程退出", adbDevice.getSerial());
    }

    private void setVideoQuality(int quality) {
        if (quality <= 40) {  //标清

        } else if (quality > 40 && quality <= 80) {  //高清

        } else {   //2k

        }
    }

    public void sendConnectInfo2Web() {
        //新连接需要先发送状态
        if (isNewConnect) {
            if (null != screenOnRequest) {  //只发第一次screen_on指令
                //向前端推送之前缓存的最新帧
                if (null != adbDevice) {
                    if (null != lastData && lastData.length > 0) {
                        SessionUtils.sendBinary(wsSession, lastData);
                        logger.debug("上位机发送缓存帧成功，大小：{}", lastData.length);
                    } else {
                        logger.warn("设备【{}】缓存帧获取为空...", adbDevice.getSerial());
                    }
                }
                //向前端推送之前缓存的最新帧后发screenOn回复
                SessionUtils.sendSuccessData(wsSession, screenOnRequest, null, "开启屏幕成功");
//                logger.debug("设备【{}】screenOn已回复", adbDevice.getSerial());
                setScreenOnRequest(null);
            }
            //发送device_connect
            isNewConnect = false;
            Map<String, Object> result = new HashMap<>();
            result.put("status", "connected");
            SessionUtils.sendMessageInitiative(wsSession, ResponseCmd.DEVICE_STATUS, adbDevice.getSerial(), result, "设备连接成功");
            logger.debug("设备【{}】连接信息已发送", adbDevice.getSerial());
        }
    }

    public void stopAndExit() {
        logger.warn("设备【{}】退出视频流..............", adbDevice.getSerial());
        asyncAgentSession.send(StopScreenVideoCommand.getInstance());
        asyncAgentSession.closeSilence();
        this.lastData = null;
        interrupt();
    }

    /**
     * 更新关联的后端会话和屏幕尺寸
     *
     * @param session
     * @param catchParam
     */
    public void startSendScreenToWeb(Session session, CatchParam catchParam) {
        this.wsSession = session;
        this.catchParam = catchParam;
        this.isNewConnect = true;
        sendConnectInfo2Web();
    }

    /**
     * 断开后端会话连接，保留接收最新帧数据
     */
    public void stopSendPic2Web() {
        this.wsSession = null;
//        logger.debug("后端会话关联已置空！屏幕获取线程是否被中断："+isInterrupted());
    }

    public void changeScreenQuality(int quality, int frameRate) {
        startScreenVideoCommand.setFrameRate(frameRate);
        setVideoQuality(quality);
        logger.debug("请求改变视频质量：{}", JSON.toJSONString(startScreenVideoCommand));
        this.asyncAgentSession.send(startScreenVideoCommand);
    }

    public void changeScreenSize(int width, int height) {
        startScreenVideoCommand.setWidth(width);
        startScreenVideoCommand.setHeight(height);
        logger.debug("请求改变视频宽高：{}", JSON.toJSONString(startScreenVideoCommand));
        this.asyncAgentSession.send(startScreenVideoCommand);
    }
}
