package net.northking.cctp.upperComputer.webSocket;

import com.alibaba.fastjson.JSON;
import net.northking.cctp.upperComputer.deviceManager.AndroidDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.IOSDeviceManager;
import net.northking.cctp.upperComputer.service.DeviceConnectionService;
import net.northking.cctp.upperComputer.utils.SpringUtils;
import net.northking.cctp.upperComputer.webSocket.entity.CmdRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@ServerEndpoint("/connectMobile")
public class DeviceConnectionWebSocket {

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

    @PostConstruct
    public void init() {
        logger.info("Init web session manager ...");
    }

    private List<String> deviceType = Arrays.asList("android","ios");

    private String type;


    /**
     * 与客户端建立Websocket会话
     *
     * @param session 会话对象
     */
    @OnOpen
    public void onOpen(Session session) {
        String queryString = session.getQueryString();
        Map<String, String> queryParams = decodeQueryString(queryString);
        String serial = queryParams.get("serial");
        type = queryParams.get("type");
        if (StringUtils.isAllBlank(serial)) {
            closeSession(session, "设备号不能为空");
            return;
        }
        if (!deviceType.contains(type)) {
            closeSession(session, "设备类型有误");
            return;
        }
        logger.info("收到建立手机【{}】的连接", serial);
        boolean isOnline = checkMobileIsOnline(serial,type);
        if (!isOnline) {
            closeSession(session, "当前设备不在线");
            return;
        }
        boolean success = SpringUtils.getBean(DeviceConnectionService.class).prepareEnvironment(serial,type,session);
        if (!success) {
            closeSession(session, "设备会话建立失败,请检查设备是否正常");
            return;
        }
        session.setMaxTextMessageBufferSize(10 * 1024 * 1024);
        session.setMaxBinaryMessageBufferSize(10 * 1024 * 1024);
        logger.info("成功建立手机【{}】会话", serial);
    }

    private boolean checkMobileIsOnline(String serial, String type) {
        logger.debug("检查设备类型：{}",type);
        if ("android".equals(type)) {
            return AndroidDeviceManager.getInstance().checkMobileIsOnline(serial);
        } else if ("ios".equals(type)){
            return IOSDeviceManager.getInstance().checkMobileIsOnline(serial);
        }
        return false;
    }

    private void closeSession(Session session, String reasonMsg) {
        try {
            session.close(new CloseReason(CloseReason.CloseCodes.TRY_AGAIN_LATER, reasonMsg));
        } catch (IOException e) {
            logger.warn("Error when close session", e);
        }
    }

    private Map<String, String> decodeQueryString(String queryString) {
        Map<String, String> queryParams = new HashMap<>();
        if (StringUtils.isNotBlank(queryString)) {
            String[] queryParamStrs = StringUtils.split(queryString, "[&]");
            if (queryParams != null && queryParamStrs.length > 0) {
                for (String paramStr : queryParamStrs) {
                    String[] param = StringUtils.split(paramStr, "=");
                    queryParams.put(param[0], param[1]);
                }
            }
        }
        return queryParams;
    }

    /**
     * 关闭调试会话
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        logger.info("收到后端关闭连接请求:[sessionId:{}]", session.getId());
        if (null != closeReason) {
            logger.info("关闭原因：{}", closeReason.getReasonPhrase());
        }
        SpringUtils.getBean(DeviceConnectionService.class).closeDeviceSession(session);
    }

    /**
     * 接收后端请求的消息
     *
     * @param msg
     */
    @OnMessage
    public void onMessage(String msg) {
        CmdRequest request = JSON.parseObject(msg, CmdRequest.class);
//        logger.info("收到后端指令请求:[cmd:{},serial:{}]", request.getCmd(), request.getSerial());
        SpringUtils.getBean(DeviceConnectionService.class).handleMessage(type,request);
    }

    @OnError
    public void onError(Session session, Throwable t) {
        logger.error(String.format("Session Error->sessionId:%s", session.getId()), t);
        onClose(session, new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "错误出现关闭"));
    }
}
