package com.sencorsta.rabs.obj.ai;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sencorsta.rabs.annotation.SceneAnnotation;
import com.sencorsta.rabs.config.AppConfig;
import com.sencorsta.rabs.obj.ai.api.Scene;
import com.sencorsta.rabs.obj.ai.scene.SceneMain;
import com.sencorsta.rabs.ui.robot.RobotUtil;
import com.sencorsta.utils.object.Jsons;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import lombok.Data;
import org.opencv.core.Mat;

import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author daibin
 */
@Data
public class AiManage {
    // 定义一个私有、静态的AiManage类型的成员变量
    private static AiManage instance;
    private Mat windowMat;

    // 将构造函数声明为私有，防止通过new创建新的对象实例
    private AiManage() {
    }

    // 定义一个公有的、静态的方法，用于返回唯一的对象实例
    public static AiManage getInstance() {
        if (instance == null) {
            instance = new AiManage();
            try {
                instance.robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace();
            }
        }
        return instance;
    }

    String windowName;
    Scene rootScene;
    Scene curScene;
    Map<String, Scene> sceneMap;
    ScheduledThreadPoolExecutor thinkPoll;
    public Robot robot;
    public Point lastClickPoint = new Point(0, 0);
    double checkPoint = 0.85;

    boolean isRunning = false;

    public void run() {
        //加载所有Scene
        fillSceneMap();
        System.out.println("sceneMap = " + Jsons.toJsonString(sceneMap));
        rootScene = sceneMap.get("SceneMain");
        curScene = null;

        thinkPoll = new ScheduledThreadPoolExecutor(1);
        thinkPoll.scheduleAtFixedRate(() -> {
            try {
                System.out.println("thinkPoll running...");
                openWindowToFront();

                updateWindow();

                if (curScene == null) {
                    //检查当前界面是否为非主场景
                    scanScene();
                }
                if (curScene.isDone()) {
                    Scene parent = curScene.getParent();
                    if (parent == null) {
                        System.out.println("当前没有任何事件。。。。。。。。");
                    } else {
                        int tempCount = 0;
                        do {
                            ThreadUtil.sleep(2000);
                            System.out.println("进入 back = " + curScene.getClass().getSimpleName());
                            curScene.back();
                            ThreadUtil.sleep(2000);
                            tempCount++;
                        }
                        while (!parent.check() && isRunning && tempCount < 30);
                        if (tempCount >= 30) {
                            scanScene();
                        } else {
                            curScene = parent;
                        }
                    }
                } else {
                    System.out.println("进入 think = " + curScene.getClass().getSimpleName());
                    curScene.think();
                    Scene undoneChildren = curScene.getChildren().stream().filter(o -> !o.isDone() && o.isOpen()).max(Comparator.comparingDouble(Scene::getPriority)).orElse(null);
                    if (ObjectUtil.isNotNull(undoneChildren)) {
                        //通用检查
                        curScene.checkBeforeEnter();

                        System.out.println("进入 open = " + undoneChildren.getClass().getSimpleName());
                        undoneChildren.open();
                        curScene = undoneChildren;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 1000, 3000, TimeUnit.MILLISECONDS);
        isRunning = true;
    }

    private void scanScene() {
        curScene = sceneMap.values().stream().filter(o -> {
            try {
                boolean check = o.check();
                if (check) {
                    System.out.println("找到当前场景:" + o.getClass().getSimpleName());
                }
                return check;
            } catch (AWTException e) {
                e.printStackTrace();
            }
            return false;
        }).findFirst().orElse(null);
        if (curScene == null) {
            System.out.println("没有找到当前场景默认使用主场景:" + rootScene.getClass().getSimpleName());
            curScene = rootScene;
        }
    }

    public void updateWindow() throws AWTException {
        Rectangle rectangle = RobotUtil.getRectangle(AiManage.getInstance().getWindowName());
        this.windowMat = RobotUtil.getWindowMat(rectangle);
    }

    private void fillSceneMap() {
        sceneMap = new HashMap<>();
        Set<Class<?>> annotatedClasses = ClassUtil.scanPackageByAnnotation("com.sencorsta.rabs.obj.ai", SceneAnnotation.class);
        // 第一次遍历添加到map
        for (Class<?> clazz : annotatedClasses) {
            try {
                if (Scene.class.isAssignableFrom(clazz)) {
                    Scene scene = (Scene) clazz.getDeclaredConstructor().newInstance();
                    sceneMap.put(clazz.getSimpleName(), scene);
                    String sceneData = AppConfig.getInstance().getSetting().getByGroup(scene.getClass().getSimpleName(), "SceneData");
                    if (sceneData != null) {
                        scene.loadData(sceneData);
                    }
                }
            } catch (InstantiationException | IllegalAccessException |
                    InvocationTargetException | NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        // 二次遍历添加父子关系
        for (Class<?> clazz : annotatedClasses) {
            try {
                if (Scene.class.isAssignableFrom(clazz)) {
                    Scene childScene = sceneMap.get(clazz.getSimpleName());
                    SceneAnnotation annotation = clazz.getAnnotation(SceneAnnotation.class);
                    String parentName = annotation.value();
                    Scene parentScene = sceneMap.get(parentName);
                    if (parentScene != null) {
                        childScene.setParent(parentScene);
                        parentScene.getChildren().add(childScene);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void openWindowToFront() {
        WinDef.HWND windowHandle = User32.INSTANCE.FindWindow(null, AiManage.getInstance().getWindowName());
        if (windowHandle == null) {
            System.out.println("Window not found: " + AiManage.getInstance().getWindowName());
        }
        User32.INSTANCE.ShowWindow(windowHandle, 9);
        User32.INSTANCE.SetForegroundWindow(windowHandle);
        ThreadUtil.sleep(200);
    }

    public void save() {
        if (sceneMap != null) {
            String sceneDataKey = "SceneData";
            AppConfig.getInstance().getSetting().getGroupedMap().clear(sceneDataKey);
            sceneMap.values().stream().sorted(Comparator.comparing(o -> o.getClass().getSimpleName())).forEach(o -> {
                AppConfig.getInstance().getSetting().setByGroup(o.getClass().getSimpleName(), sceneDataKey, o.getData());
            });
            AppConfig.getInstance().saveAll();
        }
    }

    public void forcePass() {
        if (curScene != null) {
            curScene.forcePass();
        }
    }

    public void clearAllData() {
        AppConfig.getInstance().getSetting().clear("SceneData");
        AppConfig.getInstance().saveAll();
    }

    public void stop() {
        thinkPoll.shutdown();
        thinkPoll.shutdownNow();
        AppConfig.getInstance().saveAll();
        isRunning = false;
    }
}
