package net.northking.cctp.upperComputer.automation;

import com.alibaba.fastjson.JSON;
import net.northking.cctp.upperComputer.automation.entity.CmdAutomationRequest;
import net.northking.cctp.upperComputer.automation.handler.AndroidAutomationHandler;
import net.northking.cctp.upperComputer.automation.handler.AutomationMessageHandler;
import net.northking.cctp.upperComputer.automation.handler.IosAutomationHandler;
import net.northking.cctp.upperComputer.deviceManager.AndroidDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.IOSDeviceManager;
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
import net.northking.cctp.upperComputer.entity.PhoneEntity;
import net.northking.cctp.upperComputer.service.DeviceConnectionService;
import net.northking.cctp.upperComputer.utils.SpringUtils;
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;

/**
 * @author : yineng.huang
 * @date : 2024/4/16 19:50
 */
@Component
@ServerEndpoint("/automation")
public class AutomationWebSocketServer {

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

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

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

    private String deviceId;

    private String type;

    private AutomationMessageHandler handler;

    private Session engineSession;


    /**
     * 与客户端建立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 success = prepareEnvironment(serial,type,session);
        if (!success) {
            closeSession(session, "设备自动化连接建立失败,请检查设备是否正常");
            return;
        }
        this.engineSession = session;
        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) {
        if ("hello".equals(msg)) {
            logger.debug("收到设备【{}】执行机的心跳.........................",deviceId);
            return;
        }
        logger.debug("设备【{}】收到执行机发送的消息：{}",deviceId,msg);
        CmdAutomationRequest request = JSON.parseObject(msg, CmdAutomationRequest.class);
        this.handler.automationHandle(request,this.engineSession);
    }

    @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, "错误出现关闭"));
    }

    private boolean prepareEnvironment(String serial, String type,Session session) {
        if ("android".equals(type)) {
            AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(serial);
            if (null == currentDevice) {
                logger.warn("当前设备【{}】已经离线",serial);
                return false;
            }
            //消息处理线程
            try {
                this.handler = new AndroidAutomationHandler(currentDevice,session);
            } catch (IOException e) {
                logger.error("创建设备【{}】自动化处理环境失败",serial,e);
                return false;
            }
            logger.info("手机[{}]初始化自动化环境完成。。。。。。。", serial);
            return true;
        } else if ("ios".equals(type)){
            PhoneEntity phoneEntity = IOSDeviceManager.getInstance().getPhoneEntity(serial);
            if (!phoneEntity.getStatus()) {
                logger.warn("当前设备【{}】不在线",phoneEntity.getUdid());
                return false;
            }
            this.deviceId = phoneEntity.getUdid();
            this.handler = new IosAutomationHandler(phoneEntity,session);
            logger.info("手机[{}]初始化环境完成。。。。。。。", serial);
            return true;
        }
        return false;
    }
}
