package net.northking.cctp.upperComputer.deviceManager;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import net.northking.cctp.upperComputer.automation.entity.ScreenInfo;
import net.northking.cctp.upperComputer.deviceManager.listener.HarmonyDeviceListener;
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.HDCConnectStatus;
import net.northking.cctp.upperComputer.driver.harmony.hdc.HDCDevice;
import net.northking.cctp.upperComputer.driver.harmony.hdc.Hdc;
import net.northking.cctp.upperComputer.driver.harmony.hyppium.AgentABI;
import net.northking.cctp.upperComputer.driver.harmony.hyppium.data.DisplaySize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 鸿蒙设备管理器
 * <br>
 * 因鸿蒙hdc的API并未完全解析完毕，因此仅支持连接本机的设备
 */
public class HarmonyDeviceManager extends AbstractDeviceManager {

    private static final Logger log = LoggerFactory.getLogger(HarmonyDeviceManager.class);

    private HarmonyDeviceListener harmonyDeviceListener = new HarmonyDeviceListener();

    private ConcurrentHashMap<String, HarmonyScreenResponseThread> screenMap = new ConcurrentHashMap<>();

    private static HarmonyDeviceManager instance;

    public static HarmonyDeviceManager getInstance() {
        if (instance == null) {
            instance = new HarmonyDeviceManager();
        }
        return instance;
    }

    public static final Gson gson = new Gson();

    /**
     * 临时工作目录，用于储存一些临时文件，需要可读写
     */
    private static String WORK_TMP_DIR;

    /**
     * 不同CPU架构的Agent文件Map
     */
    private static final ConcurrentHashMap<AgentABI, File> AGENT_ABI_MAP = new ConcurrentHashMap<>();

    /**
     * 当前系统设备列表
     */
    private final ArrayList<HarmonyDevice> deviceList = new ArrayList<>();

    /**
     * Harmony设备初始化线程
     */
    private ConcurrentHashMap<String, HarmonyProvider> onlineDeviceInitMap = new ConcurrentHashMap<>();

    private HarmonyDeviceManager() {
        WORK_TMP_DIR = UpperComputerManager.getInstance().getApplicationPath();
        log.debug("临时目录：{}",UpperComputerManager.getInstance().getApplicationPath());
        if (!setWorkTmpDir(WORK_TMP_DIR)) {
            throw new RuntimeException("无法使用当前指定的临时工作目录，请先指定可用目录再使用HarmonyDeviceManager");
        }
        if (!Hdc.getInstance().isObserveDeviceRunning()) {
            Hdc.getInstance().startObserveDevice();
        }
        Hdc.getInstance().addHDCDeviceListener(harmonyDeviceListener);
        registerAgentFile(AgentABI.ARM64, WORK_TMP_DIR + "/uitest_agent_v1.1.0.so");
    }

    /**
     * 设置临时工作目录
     * <br>
     * 如果有需求，应该在使用HarmonyDeviceManager之前就应该设置
     *
     * @param path 路径
     * @return 是否设置成功，如果路径存在问题，则会失败
     */
    public static boolean setWorkTmpDir(String path) {
        if (path == null || path.isEmpty()) {
            log.error("设置的临时工作目录参数为空");
            return false;
        }
        File dirFile = new File(path);
        if (!dirFile.exists()) {
            if (!dirFile.mkdirs()) {
                log.error("创建临时工作目录失败： {}", path);
                return false;
            }
        }
        if (!dirFile.isDirectory()) {
            log.error("设置的临时工作目录路径不是文件夹");
            return false;
        }
        if (!dirFile.canRead()) {
            log.error("设置的临时工作目录无法读取");
            return false;
        }
        if (!dirFile.canWrite()) {
            log.error("设置的临时工作目录无法写入");
            return false;
        }
        WORK_TMP_DIR = dirFile.getAbsolutePath();
        return true;
    }

    /**
     * 获取工作临时目录下的文件对象
     *
     * @param filename 文件名
     * @return 文件对象
     */
    public static File getWorkTmpFile(String filename) {
        return new File(WORK_TMP_DIR + "/" + filename);
    }

    /**
     * 注册一个agent文件
     *
     * @param abi  架构类型
     * @param path 文件路径
     * @return 是否注册成功
     */
    public static boolean registerAgentFile(AgentABI abi, String path) {
        File file = new File(path);
        if (!file.exists()) {
            log.error("[registerAgentFile] Agent文件不存在: {}", path);
            return false;
        }
        if (!file.isFile()) {
            log.error("[registerAgentFile] Agent路径不是文件: {}", path);
            return false;
        }
        if (!file.canRead()) {
            log.error("[registerAgentFile] Agent文件不可读: {}", path);
            return false;
        }
        AGENT_ABI_MAP.put(abi, file);
        return true;
    }

    public static File getAgentFile(AgentABI abi) {
        return AGENT_ABI_MAP.get(abi);
    }

    public ArrayList<HarmonyDevice> getDeviceList() {
        return deviceList;
    }


    @Override
    public void stopWebScreen(String udid, Session session) {
        HarmonyScreenResponseThread screenThread = screenMap.remove(udid);
        if (null != screenThread) {
            screenThread.stopWebSessionTransform(session);
        } else {
            log.info("手机【{}】不存在推图的线程",udid);
        }
    }

    @Override
    public List<String> getOnlineDevice() {
        Enumeration<String> keys = onlineDeviceInitMap.keys();
        List<String> ids = new ArrayList<>();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            ids.add(key);
        }
        return ids;
    }

    @Override
    public boolean checkMobileIsOnline(String serial) {
        HarmonyProvider provider = onlineDeviceInitMap.get(serial);
        if (null != provider) {
            return true;
        }
        return false;
    }

    @Override
    public void shutdown() {
        Hdc.getInstance().stopObserveDevice();  //关闭hdc-server
        synchronized (onlineDeviceInitMap) {  //关闭harmony设备的agent
            for (Map.Entry<String, HarmonyProvider> entry : onlineDeviceInitMap.entrySet()) {
                HarmonyProvider provider = entry.getValue();
                provider.exitDeviceInit();
            }
            onlineDeviceInitMap.clear();
        }
        //todo:设备和投屏
    }

    public void handleHarmonyDevice(ArrayList<HDCDevice> currentDevices) {
        ArrayList<HarmonyDevice> ableDevice = new ArrayList<HarmonyDevice>();
        ArrayList<HarmonyDevice> lostDevice = new ArrayList<HarmonyDevice>();
        for (HDCDevice hdcDevice : currentDevices) {
            boolean found = false;
            for (HarmonyDevice device : deviceList) {
                if (device.getHdcDevice().getConnectKey().equals(hdcDevice.getConnectKey())) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                if (hdcDevice.getConnectStatus() == HDCConnectStatus.CONNECTED) {
                    HarmonyDevice device = new HarmonyDevice(hdcDevice);
                    device.enableTestMode();
                    ableDevice.add(device);
                } else {
                    lostDevice.add(new HarmonyDevice(hdcDevice));
                }
            }
        }
        deviceList.addAll(ableDevice);
        deviceList.addAll(lostDevice);

        //更新状态
        for (HarmonyDevice device : deviceList) {
            boolean found = false;
            for (HDCDevice hdcDevice : currentDevices) {
                if (device.getHdcDevice().getConnectKey().equals(hdcDevice.getConnectKey())) {
                    found = true;
                    if (device.getHdcDevice().getConnectStatus() != hdcDevice.getConnectStatus()) {
                        if (device.getHdcDevice().getConnectStatus() == HDCConnectStatus.CONNECTED) {
                            lostDevice.add(device);
                        } else if (hdcDevice.getConnectStatus() == HDCConnectStatus.CONNECTED) {
                            device.enableTestMode();
                            ableDevice.add(device);
                        }
                    }
                    device.setHdcDevice(hdcDevice);
                    break;
                }
            }

            if (!found) {
                device.getHdcDevice().setConnectStatus(HDCConnectStatus.OFFLINE);
                lostDevice.add(device);
            }
        }
        for (HarmonyDevice device : ableDevice) {
            onLineHarmonyDevice(device);
        }
        for (HarmonyDevice device : lostDevice) {
            offlineDevice(device.getHdcDevice().getConnectKey());
        }
    }

    private void onLineHarmonyDevice(HarmonyDevice device) {
        HDCDevice hdcDevice = device.getHdcDevice();
        log.info("新上来设备：{}", JSON.toJSONString(hdcDevice));
        HarmonyProvider harmonyProvider = null;
        try {
            harmonyProvider = new HarmonyProvider(device);
        } catch (IOException e) {
            log.error("启动设备【{}】上的agent程序失败",hdcDevice.getConnectKey(),e);
            return;
        }
        log.info("设备【{}】的初始化环境准备完成",hdcDevice.getConnectKey());
        onlineDeviceInitMap.put(hdcDevice.getConnectKey(), harmonyProvider);
        DisplaySize screenSize = harmonyProvider.getScreenSize();
        int displayRotation = harmonyProvider.getDisplayRotation();
        ScreenInfo screenInfo = new ScreenInfo();
        screenInfo.setWidth(screenSize.width);
        screenInfo.setHeight(screenSize.height);
        screenInfo.setRotation(displayRotation);
        setScreenInfo(hdcDevice.getConnectKey(),screenInfo);
        publishDeviceOnlineToWebConnection(hdcDevice.getConnectKey());
    }

    @Override
    public void offlineDevice(String serial) {
        HarmonyProvider provider = onlineDeviceInitMap.remove(serial);
        if (null != provider) {
            provider.exitDeviceInit();
        }
        offlineDeviceFromDeviceManager(serial);
        publishDeviceOfflineToWebConnection(serial);
    }

    public HarmonyDevice getCurrentDevice(String deviceId) {
        for (HarmonyDevice harmonyDevice : deviceList) {
            if (deviceId.equals(harmonyDevice.getHdcDevice().getConnectKey())) {
                return harmonyDevice;
            }
        }
        return null;
    }

    public HarmonyProvider getCurrentDeviceProvider(String serial){
        return onlineDeviceInitMap.get(serial);
    }


    public HarmonyScreenResponseThread getScreenThread(String serial) {
        return screenMap.get(serial);
    }

    public void saveScreenThread(String serial, HarmonyScreenResponseThread harmonyScreenResponseThread) {
        screenMap.put(serial, harmonyScreenResponseThread);
    }

    public void removeScreenThread(String serial) {
        screenMap.remove(serial);
        log.info("移除手机【{}】的屏幕线程",serial);
    }
}
