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

import com.alibaba.fastjson.JSON;
import net.northking.cctp.upperComputer.constants.AndroidHotKeyCodeEnum;
import net.northking.cctp.upperComputer.constants.HarmonyKeyBoardCodeEnum;
import net.northking.cctp.upperComputer.constants.KeyBoardCodeEnum;
import net.northking.cctp.upperComputer.constants.ResponseCmd;
import net.northking.cctp.upperComputer.deviceManager.HarmonyDeviceManager;
import net.northking.cctp.upperComputer.deviceManager.screen.HarmonyScreenResponseThread;
import net.northking.cctp.upperComputer.deviceManager.thread.HarmonyProvider;
import net.northking.cctp.upperComputer.driver.harmony.HarmonyDevice;
import net.northking.cctp.upperComputer.driver.harmony.hdc.HarmonyKeyCode;
import net.northking.cctp.upperComputer.driver.harmony.hyppium.data.DisplaySize;
import net.northking.cctp.upperComputer.exception.ExecuteException;
import net.northking.cctp.upperComputer.exception.ParamMistakeException;
import net.northking.cctp.upperComputer.utils.SessionUtils;
import net.northking.cctp.upperComputer.webSocket.entity.CmdRequest;
import net.northking.cctp.upperComputer.webSocket.entity.ParamCheck;
import net.northking.cctp.upperComputer.webSocket.entity.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.util.*;

/**
 * @author : yineng.huang
 * @date : 2024/10/22 15:29
 */
public class HarmonyMessageHandlerThread extends AbstractMessageHandler{

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

    private HarmonyDevice harmonyDevice;

    private boolean shiftDown = false;

    private boolean ctrlDown = false;

    private boolean altDown = false;

    private boolean capsDown = false;

    private Point lastClickPoint;

    private HarmonyGetNodeTreeThread nodeTreeThread;

    private List<String> capsUpLetters = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");

    private List<String> capsDownLetters = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");


    public HarmonyMessageHandlerThread(HarmonyDevice currentDevice, Session session){
        this.harmonyDevice = currentDevice;
        this.session = session;
        this.serial = currentDevice.getHdcDevice().getConnectKey();
        setName("[" + serial + "-handleMsg]");
        initDeviceRequireParam();
        logger.info("设备【{}】的消息处理线程初始化完毕..........................", this.serial);
    }

    @Override
    public void stopAndExit() {
        logger.info("收到关闭手机【{}】连接的指令.......................",this.serial);
        HarmonyDeviceManager.getInstance().stopWebScreen(this.serial,session);
        cmdQueues.clear();
        interrupt();
    }

    @Override
    public void handleScreenOn(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck width = ParamCheck.build().name("width").type("int").withMin(0).withMax(catchParam.getRealWidth());
        ParamCheck height = ParamCheck.build().name("height").type("int").withMin(0).withMax(catchParam.getRealHeight());
        ParamCheck quality = ParamCheck.build().name("quality").type("int").withMin(0).withMax(100);
        ParamCheck framerate = ParamCheck.build().name("framerate").type("int").withMin(0).withMax(100);
        ParamCheck rotation = ParamCheck.build().name("rotation").type("int").rangeSelection().withIntValue(Arrays.asList(0, 1, 2, 3));
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, width, height, quality, framerate, rotation);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        int widthUse = (int) params.get("width");
        catchParam.setWidth(widthUse);
        int heightUse = (int) params.get("height");
        catchParam.setHeight(heightUse);
        int qualityUse = (int) params.get("quality");
        catchParam.setQuality(qualityUse);
        int frameRateUse = (int) params.get("framerate");
        catchParam.setFrameRate(frameRateUse);
        int rotationUse = (int) params.get("rotation");
        catchParam.setRotation(rotationUse);
        logger.debug("开启屏幕=====>width：{} height:{} quality:{} frameRate:{},rotation:{}", widthUse, heightUse, qualityUse, frameRateUse, rotationUse);
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        HarmonyScreenResponseThread harmonyScreenResponseThread = HarmonyDeviceManager.getInstance().getScreenThread(serial);
        if (null == harmonyScreenResponseThread) {
            harmonyScreenResponseThread = new HarmonyScreenResponseThread(session, harmonyDevice);
            HarmonyDeviceManager.getInstance().saveScreenThread(serial, harmonyScreenResponseThread);
            //开启手机端的屏幕
            boolean success = harmonyProvider.startCaptureScreenImageStream(0.5f, harmonyScreenResponseThread);
            if (success) {
                harmonyScreenResponseThread.setScreenOnRequest(session, request);
                harmonyScreenResponseThread.startSendScreenToWeb(session, catchParam);
                logger.info("开启设备【{}】的图片流成功", this.serial);
            } else {
                logger.info("开启设备【{}】的图片流失败", this.serial);
                Map<String, Object> result = new HashMap<>();
                result.put(ResponseCmd.DeviceStatus.STATUS, ResponseCmd.DeviceStatus.DISCONNECT);
                SessionUtils.sendMessageInitiative(session, ResponseCmd.DEVICE_STATUS, this.serial, result, "开启设备的图片流失败，正在重试");
            }
        } else {
            logger.info("设备【{}】的屏幕已经开启了，通知往前端发即可", this.serial);
            harmonyScreenResponseThread.setScreenOnRequest(session, request);
            harmonyScreenResponseThread.startSendScreenToWeb(session, catchParam);
        }


    }

    @Override
    public void changeScreenSize(CmdRequest request) {

    }

    @Override
    public void changeScreenQuality(CmdRequest request) {

    }


    @Override
    public void screenShot(CmdRequest request) {

    }

    @Override
    public void touchDown(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck xCheck = ParamCheck.build().name("x").type("double").withMin(0).withMax(catchParam.getWidth());
        ParamCheck yCheck = ParamCheck.build().name("y").type("double").withMin(0).withMax(catchParam.getHeight());
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, xCheck, yCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        Point point = calculatePoint(params);
        lastClickPoint = point;
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        boolean success = harmonyProvider.touchDown(point.getX().intValue(), point.getY().intValue());
        if (success) {
            SessionUtils.sendSuccessData(session, request, null, "摁下成功");
        } else {
            logger.warn("设备【{}】摁下失败............................",this.serial);
        }
    }

    @Override
    public void touchMove(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck xCheck = ParamCheck.build().name("x").type("double").withMin(0).withMax(catchParam.getWidth());
        ParamCheck yCheck = ParamCheck.build().name("y").type("double").withMin(0).withMax(catchParam.getHeight());
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, xCheck, yCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        Point point = calculatePoint(params);
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        boolean success = harmonyProvider.touchMove(point.getX().intValue(), point.getY().intValue());
        if (success) {
            SessionUtils.sendSuccessData(session, request, null, "滑动成功");
        } else {
            logger.warn("设备【{}】滑动失败............................",this.serial);
        }

    }

    @Override
    public void touchUp(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck xCheck = ParamCheck.build().name("x").type("double").withMin(0).withMax(catchParam.getWidth());
        ParamCheck yCheck = ParamCheck.build().name("y").type("double").withMin(0).withMax(catchParam.getHeight());
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, xCheck, yCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        Point point = calculatePoint(params);
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        boolean success = harmonyProvider.touchUp(point.getX().intValue(), point.getY().intValue());
        if (success) {
            SessionUtils.sendSuccessData(session, request, null, "抬起成功");
        } else {
            logger.warn("设备【{}】抬起失败............................",this.serial);
        }
    }

    @Override
    public void inputKeyPress(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck keyCodeCheck = ParamCheck.build().name("key").type("string");
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, keyCodeCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        String key = (String) params.get("key");
        int code = AndroidHotKeyCodeEnum.getCode(key);
        if (code < 0) {
            SessionUtils.sendFailureMessage(session, request, "热键[" + key + "]不存在");
            return;
        }
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        boolean success = false;
        switch (key) {
            case "home":
                success = harmonyProvider.pressHome();
                break;
            case "appSwitch":
                success = harmonyProvider.pressRecentApp();
                break;
            case "back":
                success = harmonyProvider.pressBack();
                break;
            case "volumeUp":
                success = harmonyProvider.pressUpVolume();
                break;
            case "volumeDown":
                success = harmonyProvider.pressDownVolume();
                break;
            case "power":
                success = harmonyProvider.pressPowerKey();
                break;
            default:
                logger.warn("没有对应的热键完成对设备的操控");
                break;
        }
        if (success) {
            SessionUtils.sendSuccessData(session, request, null, "热键处理成功");
        } else {
            logger.warn("设备【{}】热键【{}】操控失败............................",this.serial,key);
        }
    }

    @Override
    public void inputType(CmdRequest request) {

    }

    @Override
    public void inputSetText(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck textCheck = ParamCheck.build().name("text").type("string").length(Integer.MAX_VALUE);
        ParamCheck clearCheck = ParamCheck.build().name("clear").type("boolean");
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, textCheck, clearCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        String text = (String) params.get("text");
        boolean clear = (boolean) params.get("clear");
        HarmonyDevice currentDevice = HarmonyDeviceManager.getInstance().getCurrentDevice(this.serial);
        if (null != currentDevice) {
            boolean success = false;
            if (null != lastClickPoint) {
                success = harmonyDevice.inputText(lastClickPoint.getX().intValue(), lastClickPoint.getY().intValue(), text);
            }
            if (success) {
                SessionUtils.sendSuccessData(session, request, null, "输入文本成功");
            } else {
                logger.warn("设备【{}】输入文本失败............................",this.serial);
            }
        } else {
            SessionUtils.sendFailureMessage(session, request, "设备掉线，输入文本失败");
        }

    }

    @Override
    public void clipboardPast(CmdRequest request) {

    }

    @Override
    public void clipboardCopy(CmdRequest request) {

    }

    @Override
    public void rotationScreen(CmdRequest request) {

    }

    @Override
    public void restartDevice(CmdRequest request) {

    }

    @Override
    public void deviceOpenCamera(CmdRequest request) {

    }

    @Override
    public void openSetting(CmdRequest request) {

    }

    @Override
    public void setWifiStatus(CmdRequest request) {

    }

    @Override
    public void openBrowser(CmdRequest request) {

    }

    @Override
    public void installApp(CmdRequest request) {

    }

    @Override
    public void inputKeyDown(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck keyCodeCheck = ParamCheck.build().name("key").type("string");
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, keyCodeCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        String key = (String) params.get("key");
        setKeyCodeStatus(key, true);  //设置按键状态
        SessionUtils.sendSuccessData(session, request, null, "摁下键[" + key + "]处理成功");
    }

    @Override
    public void inputKeyUp(CmdRequest request) {
        Map<String, Object> data = request.getData();
        ParamCheck keyCodeCheck = ParamCheck.build().name("key").type("string");
        Map<String, Object> params = null;
        try {
            params = checkParam(data, false, keyCodeCheck);
        } catch (Exception e) {
            logger.error("参数校验失败！", e);
            if (e instanceof ParamMistakeException) {
                SessionUtils.sendFailureMessage(session, request, e.getMessage());
                return;
            }
        }
        String key = (String) params.get("key");
        setKeyCodeStatus(key, false);
        int code = HarmonyKeyBoardCodeEnum.getCode(key, !shiftDown);
        if (code < 0) {
            SessionUtils.sendFailureMessage(session, request, "键[" + key + "]不存在");
            return;
        }
        List<Integer> codeList = new ArrayList<>();
        if (altDown) {
            codeList.add(HarmonyKeyCode.KEYCODE_ALT_LEFT);
        }
        if ((capsDown && !shiftDown) || (!capsDown && shiftDown)) {
            codeList.add(HarmonyKeyCode.KEYCODE_SHIFT_LEFT);
        }
        if (ctrlDown) {
            codeList.add(HarmonyKeyCode.KEYCODE_CTRL_LEFT);
        }
        codeList.add(code);
        logger.debug("输入code:{}", JSON.toJSONString(codeList));
        HarmonyDevice currentDevice = HarmonyDeviceManager.getInstance().getCurrentDevice(this.serial);
        if (null != currentDevice) {
            boolean success = harmonyDevice.keyEvent(codeList);
            if (success) {
                SessionUtils.sendSuccessData(session, request, null, "抬起键[" + key + "]处理成功");
            } else {
                logger.warn("设备【{}】输入文本失败............................",this.serial);
            }
        } else {
            SessionUtils.sendFailureMessage(session, request, "设备掉线，抬起键[" + key + "]失败");
        }
    }

    @Override
    public void getAppList(CmdRequest request) {

    }

    @Override
    public void uninstallApp(CmdRequest request) {

    }

    @Override
    public void sendShellToDevice(CmdRequest request) {

    }

    @Override
    public void startLogcat(CmdRequest request) {

    }

    @Override
    public void stopLogcat(CmdRequest request) {

    }

    @Override
    public void startPerf(CmdRequest request) {

    }

    @Override
    public void stopPerf(CmdRequest request) {

    }

    @Override
    public void closeADBDebug(CmdRequest request) {

    }

    @Override
    public void openADBDebug(CmdRequest request) {

    }

    @Override
    public void pullFileFromDevice(CmdRequest request) {

    }

    @Override
    public void pushFileToDevice(CmdRequest request) {

    }

    @Override
    public void getFileList(CmdRequest request) {

    }

    @Override
    public void downloadLogcat(CmdRequest request) {

    }

    @Override
    public void startUiNode(CmdRequest request) {
        if (null == nodeTreeThread || nodeTreeThread.isInterrupted() || !nodeTreeThread.isAlive()) {
            try {
                HarmonyProvider harmonyProvider = HarmonyDeviceManager.getInstance().getCurrentDeviceProvider(this.serial);
                if (null == harmonyProvider) {
                    SessionUtils.sendFailureMessage(session, request, "设备还未准备就绪，请稍后再试");
                    return;
                }
                nodeTreeThread = new HarmonyGetNodeTreeThread(session,this.serial,request);
            } catch (Exception e) {
                if (e instanceof ExecuteException) {
                    SessionUtils.sendFailureMessage(session, request, e.getMessage());
                } else {
                    SessionUtils.sendFailureMessage(session, request, "获取设备节点失败");
                }
                return;
            }
            nodeTreeThread.start();
        } else {
            nodeTreeThread.startGetNodeTree(request);
        }
    }

    @Override
    public void stopUiNode(CmdRequest request) {
        if (null != nodeTreeThread) {
            nodeTreeThread.stopGetNodeTree(request);
            return;
        }
        SessionUtils.sendSuccessData(session, request, null,"该设备尚未开启获取节点树");
    }

    @Override
    public void getNodeTreeOnce(CmdRequest request) {

    }

    @Override
    public void clearAndCloseDeviceAgentConnection() {

    }

    @Override
    public void reConnectDeviceAgent() {

    }

    @Override
    public void initDeviceRequireParam() {
        logger.info("获取手机【{}】的实际宽高............................",this.serial);
        HarmonyProvider harmonyProvider = getHarmonyProvider();
        DisplaySize screenSize = harmonyProvider.getScreenSize();
        if (null == screenSize) {
            throw new ParamMistakeException(String.format("获取手机【%s】实际宽高失败,请稍后再试！", this.serial));
        }
        catchParam.setRealHeight(screenSize.height);
        catchParam.setRealWidth(screenSize.width);
        logger.info("手机【{}】的实际宽:{}高:{}............................", this.serial,catchParam.getRealWidth(), catchParam.getRealHeight());
    }

    private HarmonyProvider getHarmonyProvider(){
        HarmonyProvider provider = HarmonyDeviceManager.getInstance().getCurrentDeviceProvider(this.serial);
        if (null == provider) {
            throw new ExecuteException("当前设备已经掉线，请检查设备");
        }
        return provider;
    }

    private Point calculatePoint(Map<String, Object> data) {
        Double x = Double.parseDouble(data.get("x") + "");
        Double y = Double.parseDouble(data.get("y") + "");
        Double realX = x.doubleValue() / catchParam.getWidth() * catchParam.getRealWidth();
        Double realY = y.doubleValue() / catchParam.getHeight() * catchParam.getRealHeight();
        return new Point(realX.floatValue(), realY.floatValue());
    }

    /**
     * 设置摁下的是否是shift,ctrl,alt
     *
     * @param key
     * @param down 摁下为true，抬起为false
     */
    private void setKeyCodeStatus(String key, boolean down) {
        if (key.equals(KeyBoardCodeEnum.KEYCODE_SHIFT_LEFT.getWebValue())) {
            shiftDown = down;
        } else if (key.equals(KeyBoardCodeEnum.KEYCODE_ALT_LEFT.getWebValue())) {
            altDown = down;
        } else if (key.equals(KeyBoardCodeEnum.KEYCODE_CTRL_LEFT.getWebValue())) {
            ctrlDown = down;
        } else if (capsUpLetters.contains(key)) {  //包含大写字母
            if (shiftDown) {  //如果是按了shift
                logger.debug("没摁大写锁定");
                capsDown = false;
            } else {
                logger.debug("摁了大写锁定");
                capsDown = true;
            }
        } else if (capsDownLetters.contains(key)) {  //小写字母
            if (shiftDown) {  //如果按了shift
                logger.debug("没摁大写锁定");
                capsDown = true;
            } else {
                logger.debug("摁了大写锁定");
                capsDown = false;
            }
        } else if (key.equals(KeyBoardCodeEnum.KEYCODE_CAPS_LOCK.getWebValue())) {
            logger.debug("摁大写锁定。。。。。。。。。。");
            capsDown = !capsDown;
        }
    }
}
