from functools import cached_property

from mower.solvers.rogue import data


class Path:
    # 定义一个类属性，表示比较规则的优先级
    _compare_rules = []

    def __init__(self, path: list[str]):
        self.path = path

    @cached_property
    def length(self):
        """路径的长度"""
        return len(self.path)

    @cached_property
    def type(self):
        """
        返回路径中每种类型节点的数量。

        示例:
        {
            "作战": 2,
            "紧急作战": 1,
            ...
        }
        """
        type_num = {}
        for node_id in self.path:
            node_type_name = data.nodes[node_id].type
            if node_type_name in type_num:
                type_num[node_type_name] += 1
            else:
                type_num[node_type_name] = 1
        if data.nodes[self.path[0]].type == "紧急作战":  # 忽略起点的紧急作战用于刷新
            type_num["紧急作战"] -= 1
        return type_num

    @property
    def idea(self):
        """路径需要的构想值"""
        idea_num = 0
        for i in range(1, len(self.path)):
            if self.path[i][0] == self.path[i - 1][0]:
                idea_num += 2
        if data.next_step[self.path[0]] == 1:
            idea_num += 1
        if data.last_node_id and data.last_node_id[0] == self.path[0][0]:
            idea_num += 2
        return idea_num

    @classmethod
    def set_compare_rules(cls, rules: list[tuple[str, bool]]):
        """
        设置比较规则列表。

        Args:
            rules: list[tuple[str, bool]]
                - 每个元组的第一个元素是比较属性或类型名称（如 "length", "紧急作战"）。
                - 第二个元素是布尔值，True 表示升序，False 表示降序。
        """
        cls._compare_rules = rules

    def __lt__(self, other: "Path"):
        """
        重载 < 运算符，根据 _compare_rules 动态比较多个属性。
        """
        if not self._compare_rules:
            raise ValueError("未定义比较规则，请先调用 set_compare_rules 设置规则。")

        for rule, ascending in self._compare_rules:
            # 获取当前规则对应的值
            if rule == "length":
                # 按路径长度比较
                self_value = self.length
                other_value = other.length
            elif rule == "idea":
                # 按构想值比较
                self_value = self.idea
                other_value = other.idea
            else:
                # 按类型数量比较
                self_value = self.type.get(rule, 0)
                other_value = other.type.get(rule, 0)

            # 如果值不相等，则进行比较
            if self_value != other_value:
                if ascending:
                    return self_value < other_value  # 升序
                else:
                    return self_value > other_value  # 降序

        # 如果所有规则都相等，则不比较
        return False

    def __repr__(self):
        return (
            f"Path({self.path},length={self.length},type={self.type},idea={self.idea})"
        )


def dfs(node_id: str, path: list, all_paths: list["Path"]):
    """
    Args:
        node_id (str): 当前节点的编号
        path (list): 当前路径，存储经过的节点编号
        all_paths (list[&quot;Path&quot;]): 保存所有路径的列表
    """
    path.append(node_id)
    if not data.nodes[node_id].next_nodes:
        all_paths.append(Path(path[:]))
    else:
        for next_node_id in data.nodes[node_id].next_nodes:
            if next_node_id not in path:
                dfs(next_node_id, path, all_paths)
    path.pop()


def get_optimal_path(
    start_id: str,
    idea_num: int = 2,
    compare_rules: list = [("紧急作战", True), ("length", False), ("idea", True)],
) -> "Path":
    """
    获取最优路径。

    Args:
        idea_num (int): 可使用的构想值

    Returns:
        Path: 最优路径
    """
    idea_num = max(idea_num, 0)
    all_paths: list["Path"] = []
    dfs(start_id, [], all_paths)
    Path.set_compare_rules(compare_rules)
    all_paths.sort()
    for path in all_paths:
        if path.idea <= idea_num:
            return path
    compare_rules.insert(0, ("idea", True))
    Path.set_compare_rules(compare_rules)
    all_paths.sort()
    return all_paths[0]
