from datetime import datetime, timedelta

import cv2

from mower.solvers.rogue import data
from mower.utils import config
from mower.utils.graph import SceneGraphSolver
from mower.utils.image import cropimg, loadres, template
from mower.utils.log import logger
from mower.utils.recognize import Scene
from mower.utils.vector import sa, vs

from .lighten_load import LightenLoadSolver
from .rogue_abandon_explore import RogueAbandonExploreSolver
from .utils.detect_node import NodeDetector
from .utils.optimal_path import Path, get_optimal_path
from .utils.utils import detect_layer, get_idea_num


class ChooseNextNodeSolver(SceneGraphSolver):
    solver_name = "选择下一个节点"

    def run(self):
        self.success = False
        self.start_time = datetime.now()
        self.idea_num = None
        super().run()
        data.next_step = {}
        if self.success and self.node_id:
            for id in data.nodes[self.node_id].next_nodes:
                data.next_step[id] = 2
            data.last_node_id = self.node_id
        logger.info(f"{data.next_step=}")

    @property
    def current_idea_num(self) -> int:
        if self.idea_num is None:
            self.idea_num = get_idea_num()
        return self.idea_num

    def get_next_node_id(self) -> str:
        layer = detect_layer()
        logger.debug(f"{self.current_idea_num=} {layer=}")
        idea_num = self.current_idea_num if layer == 5 else self.current_idea_num - 2
        if config.conf.rogue.mode == 1:
            compare_rules: list = [("紧急作战", True), ("length", True), ("idea", True)]
        elif config.conf.rogue.mode == 0:
            compare_rules: list = [
                ("紧急作战", True),
                ("length", False),
                ("idea", True),
            ]
            if layer == 2:
                compare_rules.insert(0, ("先行一步", False))
        valid_road: list["Path"] = []
        for node_id in data.next_step:
            refresh_time = data.next_step[node_id]
            if not refresh_time:
                continue
            road = get_optimal_path(node_id, idea_num)
            if road.idea > self.current_idea_num:
                continue
            valid_road.append(road)
        if not valid_road:
            self.node_id = ""
            return

        Path.set_compare_rules(compare_rules)
        valid_road.sort()
        logger.debug(f"{valid_road=}")
        self.node_id = valid_road[0].path[0]
        self.need_idea = valid_road[0].idea

    def get_node_pos(self, node_id: str, scope=((0, 150), (1600, 880))):
        img = cropimg(config.recog.img, scope)
        img = cv2.GaussianBlur(img, (5, 5), 0)
        score, scope = template(data.scene_image, img)
        node_scope = data.nodes[node_id].scope
        logger.debug(f"{score=} {scope=} {node_scope=}")
        if score < 0.3:
            return ((-1, -1), (-1, -1))
        res_scope = vs(node_scope[0], scope[0]), vs(node_scope[1], scope[0])
        res_scope = sa(res_scope, (0, 150))
        return res_scope

    def check_node_current_type(self, match_scope) -> str:
        for type in data.node_type[config.conf.maa_rg_theme]:
            res_name = f"rogue/node_{config.conf.maa_rg_theme}/{type}"
            res = loadres(res_name)
            score, scope = template(config.recog.img, res, match_scope)
            if score > 0.75:
                return type
        return "未知"

    def transition(self):
        if datetime.now() - self.start_time > timedelta(minutes=2):
            logger.error("选择节点超时")
            RogueAbandonExploreSolver().run()
            return True
        if (scene := self.scene()) == Scene.ROGUE_MAIN:
            if self.animation(((0, 150), (1600, 880)), interval=0.1, ratio=0.1):
                return
            if len(data.next_step) == 0:
                NodeDetector()
            self.get_next_node_id()
            if not self.node_id:
                RogueAbandonExploreSolver().run()
                return True
            scope = self.get_node_pos(self.node_id)
            if scope[1][0] < 0:
                self.swipe_ext([(1000, 870), (1820, 870)], [200], 400, 0.1)
            elif scope[0][0] > 1920:
                self.swipe_ext([(1820, 870), (1000, 870)], [200], 400, 0.1)
            else:
                self.ctap(scope, 2)
        elif scene == Scene.ROGUE_NODE_BEFORE_GO:
            if self.animation(((0, 150), (1600, 880)), interval=0.1, ratio=0.1):
                return
            if len(data.next_step) == 0:
                self.scene_graph_step(Scene.ROGUE_MAIN)
                return
            self.get_next_node_id()
            if not self.node_id:
                return RogueAbandonExploreSolver().run()

            if not data.nodes[self.node_id].next_nodes:  # 最后一个节点不好匹配
                self.ctap("rogue/go", 3)
                return

            scope = self.get_node_pos(self.node_id, ((0, 150), (960, 880)))
            if scope[1][0] < 0 or scope[0][0] > 960:
                self.scene_graph_step(Scene.ROGUE_MAIN)
                return

            if not self.find("rogue/node_be_choosed", scope=sa(scope, (-150, 0))):
                self.tap(scope)
                return
            node_type = self.check_node_current_type(scope)
            if node_type in ["作战", "紧急作战"]:
                if node_type != data.nodes[self.node_id].type:
                    data.next_step[self.node_id] -= 1
                    logger.debug(
                        f"{type=} {data.nodes[self.node_id].type=} {data.next_step=}"
                    )
                    data.nodes[self.node_id].type = node_type
                    if data.next_step[self.node_id] == 0:  # 第二次刷新时,构想数量-1
                        self.idea_num -= 1
                    return
                self.tap("rogue/refresh")
                return
            self.ctap("rogue/go", 3)
            self.success = True

        elif scene in [Scene.ROGUE_REFRESH_CONFIRM, Scene.ROGUE_DOUBLE_CONFIRM]:
            self.ctap("rogue/double_confirm/main", 3, x_rate=1)

        elif scene == Scene.ROGUE_SARKAZ_LOAD:
            LightenLoadSolver().run()

        elif scene == Scene.ROGUE_CONFUSION_WARNING:
            if self.find("rogue/double_confirm/check_blank"):
                self.ctap("rogue/double_confirm/check_blank", 3)
            else:
                self.ctap("rogue/double_confirm/main", 3, x_rate=1)

        elif scene in self.waiting_scene:
            self.waiting_solver()
        else:
            return True
