package net.northking.cctp.mobile.socket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.northking.cctp.mobile.api.report.service.DeviceUseReportDetailApiService;
import net.northking.cctp.mobile.constants.MobileConnectionConstants;
import net.northking.cctp.mobile.db.service.DeviceUseReportService;
import net.northking.cctp.mobile.dto.report.DeviceLogDto;
import net.northking.cctp.mobile.dto.report.DeviceUseReportDetailAddDto;
import net.northking.cctp.mobile.dto.report.DeviceUseReportQueryDto;
import net.northking.cctp.mobile.entity.UpperWSResponse;
import net.northking.cctp.mobile.entity.WSResponse;
import net.northking.cctp.mobile.util.JsonUtils;
import net.northking.cctp.mobile.util.SpringUtils;
import net.northking.cctp.mobile.util.WSUtils;
import org.apache.commons.lang.StringUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.CloseReason;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class UpperWebSocketClient extends WebSocketClient {
    private final Logger logger = LoggerFactory.getLogger(UpperWebSocketClient.class);

    private Session webSession;

    private String deviceId;

    private String sessionId;

    private long received = 1;
    private long send = 1;

    private RemoteEndpoint.Basic basicRemote;

    public UpperWebSocketClient(URI uri, Session webSession, String deviceId, String sessionId) {
        super(uri);
        this.webSession = webSession;
        this.deviceId = deviceId;
        this.sessionId = sessionId;
        basicRemote = webSession.getBasicRemote();
    }

    public boolean isConnected() {
        int chkTimes = 0;
        while (!this.getReadyState().equals(ReadyState.OPEN) && chkTimes++ < 3) {
            logger.info("Connecting ...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                logger.error("Error", e);
            }
        }
        return this.getReadyState().equals(ReadyState.OPEN);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        logger.debug("服务端连接上位机ws成功。。。。。。。。。");
    }

    @Override
    public void onMessage(String msg) {
//        logger.debug("服务端接收到上位机信息，msg:{}", msg);
        try {
            UpperWSResponse msgResponse = JsonUtils.fromJsonString(msg, UpperWSResponse.class);
            String cmd = msgResponse.getCmd();
            logger.info("cmd: " + cmd);
            switch (cmd) {
                case MobileConnectionConstants.CommandConstants.CMD_WIFI_CHANGE:
                    handleUpperMsgActive(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_DISPLAY_CHANGE:
                    handleUpperMsgActive(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_DEVICE_STATUS:
                    handleUpperMsgActive(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_SCREEN_ON:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_SCREEN_SIZE:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_SCREEN_QUALITY:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_TOUCHDOWN:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_TOUCHMOVE:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_TOUCHUP:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_KEYPRESS:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_KEYDOWN:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_KEYUP:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_TYPE:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_INPUT_SETTEXT:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_CLIPBOARD_PAST:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_CLIPBOARD_COPY:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_DISPLAY_ROTATE:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_DEVICE_START_NODE:
                    handleUpperMsgForward(msgResponse);
                    break;
                case MobileConnectionConstants.CommandConstants.CMD_DEVICE_STOP_NODE:
                    handleUpperMsgForward(msgResponse);
                    break;
                default:
                    logger.warn("指令不符合要求");
                    break;
            }
        } catch (Exception e) {
            logger.warn("消息处理失败：",e);
        }

    }

    @Override
    public void onMessage(ByteBuffer bytes) {
        //屏幕流直接转发给前端
//        byte[] screenStream = bytes.array();
        logger.debug("收到设备【{}】上位机传输的图片数量：{}",deviceId,received++);
        WSUtils.sendBytes(basicRemote, bytes, deviceId);
        logger.debug("发送设备【{}】到前端的图片数量{}",deviceId,send++);
    }

    @Override
    public void send(String text) {
        super.send(text);
    }

    @Override
    public void onClose(int i, String s, boolean b) {
        logger.warn("设备【{}】的后台服务与上位机的ws断开，返回码：{},断开原因：{}", deviceId, i, s);
        if (null != webSession) {
            UpperWSResponse msgResponse = new UpperWSResponse();
            msgResponse.setCmd(MobileConnectionConstants.CommandConstants.CMD_DEVICE_STATUS);
            msgResponse.setFinish(true);
            msgResponse.setMessage("上位机关闭连接");
            msgResponse.setSerial(deviceId);
            msgResponse.setSuccess(false);
            Map<String, Object> result = new HashMap<>();
            result.put("status", "disconnect");
            result.put("message", "上位机连接断开");
            msgResponse.setData(result);
            handleUpperMsgActive(msgResponse);
        }
    }

    @Override
    public void onError(Exception e) {
        logger.warn("服务与上位机的ws连接错误，原因：", e);
    }


    public void closeUpperConnection() {
        webSession = null;
        close(CloseReason.CloseCodes.NORMAL_CLOSURE.getCode());
    }

    /**
     * 转发消息
     *
     * @param msgResponse
     */
    private void handleUpperMsgForward(UpperWSResponse msgResponse) {
        WSResponse wsResponse = WSResponse.buildResponse(sessionId, msgResponse);
        WSUtils.sendText(basicRemote, JsonUtils.toJson(wsResponse), deviceId);
    }

    /**
     * 主动推送消息
     */
    private void handleUpperMsgActive(UpperWSResponse msgResponse) {
        //根据返回结果决定返回内容
        WSResponse wsResponse = WSResponse.buildResponse(msgResponse.getCmd(), sessionId, msgResponse.getData());
        WSUtils.sendText(webSession, JsonUtils.toJson(wsResponse), deviceId);
    }
}
