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

import net.northking.cctp.upperComputer.constants.ResponseCmd;
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 javax.websocket.Session;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author : yineng.huang
 * @date : 2024/7/18 17:48
 */
public abstract class ImageScreenResponse extends Thread{

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

    protected List<Session> webSessions = new ArrayList<>(3);  //与微服务之间的连接session，传送屏幕的

    protected ScreenRecorder screenRecorder;

    protected boolean sendDeviceStatus = true;

    protected Map<String,CmdRequest> allConnectionScreenOnRequestMap;  //只是第一次连接需要，发送给前端代表连接成功

    protected String deviceId;

    protected CatchParam catchParam;

    protected byte[] lastData;

    public void setCatchParam(CatchParam catchParam) {
        this.catchParam = catchParam;
    }

    public void startRecordScreen(String tenantId, int width, int height, String taskId) {
        logger.info("收到设备【{}】的录屏请求，当前请求的taskId为：{}",deviceId,taskId);
        if (null != screenRecorder) {
            logger.warn("上一次设备【{}】的录频还在跑呢，上一次跑的taskId为：{}",deviceId,screenRecorder.getTaskId());
            String previousRecordPath = screenRecorder.endRecord();
            logger.warn("设备【{}】上一次的录频结束，taskId为：{}，上传的地址为：{}",deviceId,screenRecorder.getTaskId(),previousRecordPath);
        }
        logger.info("开启设备【{}】的录屏请求，当前请求的taskId为：{}",deviceId,taskId);
        SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        String dateFormat = format.format(new Date());
        String videoName = deviceId + "_" + dateFormat + ".mp4";
        screenRecorder = new ScreenRecorder(deviceId, videoName, tenantId,taskId, width, height);
        screenRecorder.startRecordVideo();
    }

    public String stopRecord() {
        String result = null;
        String taskId = null;
        if (null != screenRecorder) {
            result = screenRecorder.endRecord();
            taskId = screenRecorder.getTaskId();
            screenRecorder = null;
        }
        if (CollectionUtils.isEmpty(webSessions)) {
            logger.info("设备【{}】在taskId:{}的录屏结束了,而且没有前端的连接，直接退出屏幕抓取的线程了.............", deviceId, taskId);
            stopFetchPic();
        } else {
            logger.info("设备【{}】在taskId:{}的录屏结束了,但是还有前端的连接再用着，先不断开.............", deviceId, taskId);
        }
        return result;
    }

    public void startSendScreenToWeb(Session session, CatchParam catchParam) {
        this.catchParam = catchParam;
        logger.info("设备【{}】当前连接了{}个web客户端...............",deviceId,this.webSessions.size());
        if (this.webSessions.size() > 1) {
            //通知前端断开连接，最多只能连接三个
            Map<String, Object> messageMap = new HashMap<>();
            messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.DISCONNECT);
            SessionUtils.sendMessageInitiative(session, ResponseCmd.DEVICE_STATUS, deviceId, messageMap, "最多支持一个客户端观察直播");
            return;
        }
        this.webSessions.add(session);
        //先发一个改变屏幕宽高的指令过去
        changeScreenSize();
        //通知前端开始连接
        Map<String, Object> messageMap = new HashMap<>();
        messageMap.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTING);
        SessionUtils.sendMessageInitiative(session, ResponseCmd.DEVICE_STATUS, deviceId, messageMap, "设备掉线了");
        logger.info("发送设备【{}】最后一张图片到前端..............",deviceId);
        if (null != this.lastData) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            try {
                logger.info("开始压缩设备【{}】最后一张图片到前端，宽：{}，高：{}..............",deviceId,catchParam.getWidth(),catchParam.getHeight());
                Thumbnails.of(new ByteArrayInputStream(this.lastData)).forceSize(catchParam.getWidth(), catchParam.getHeight()).toOutputStream(outputStream);
                logger.info("压缩完毕设备【{}】最后一张图片到前端..............",deviceId);
                byte[] data = outputStream.toByteArray();
                Map<String, Object> result = new HashMap<>();
                result.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.CONNECTED);
                SessionUtils.sendMessageInitiative(session, ResponseCmd.DEVICE_STATUS, deviceId, result, "设备已连接");
                SessionUtils.sendBinary(session, data);
            } catch (Exception e) {
                logger.info("设备【{}】在编码第一张图片的时候出现了错误，等一下张图片再发..............",deviceId,e);
                this.sendDeviceStatus = true;
            }finally {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            logger.info("发送设备【{}】最后一张图片是空，获取到了再发..............",deviceId);
            this.sendDeviceStatus = true;
        }

    }

    public abstract void changeScreenSize();

    public void setSendDeviceStatus(boolean sendDeviceStatus) {
        this.sendDeviceStatus = sendDeviceStatus;
    }

    public void stopWebSessionTransform(Session session) {
        logger.info("移除设备【{}】的web投屏连接,sessionId为：{}...............",deviceId,session.getId());
        webSessions.remove(session);
        logger.info("设备【{}】的web投屏连接数还剩下：{}...............",deviceId,webSessions.size());
        if (webSessions.size() > 0) {
            logger.info("设备【{}】还有其他人连着这个屏幕的，还保留一下这个线程............",deviceId);
        } else {
            if (null != screenRecorder) {
                logger.info("设备【{}】还录着屏幕的，还保留一下这个线程............", deviceId);
            } else {
                logger.info("设备【{}】没有web端连接，也没有录频，退出............", deviceId);
                stopFetchPic();
            }
        }
    }

    public void setScreenOnRequest(Session session, CmdRequest screenOnRequest) {
        SessionUtils.sendSuccessData(session, screenOnRequest, null, "开启屏幕成功");
    }

    public abstract void stopFetchPic();
}
