import os, sys
from abc import ABC, abstractmethod
from enum import Enum
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from core.defines import ReleaseErr
from thirdparty.py_trees.behaviour import Behaviour
from thirdparty.py_trees.common import Access
from thirdparty.py_trees.composites import Selector, Parallel, Sequence, Composite
# from thirdparty.py_trees.decorators import Decorator
from thirdparty.py_trees import blackboard
from thirdparty.py_trees.common import ParallelPolicy
from thirdparty.py_trees.behaviour import Behaviour
import typing
from core.logger import get_logger

log = get_logger()

class ReleaseFlowBlackboard(blackboard.Client):
    """
    重载blackboard.Client用于适配一些我们的需求
    每个节点访问其所需要的数据的时候都需要先进行注册，注册之后方可访问
    """
    def register_key(self, key: str, access: Access = Access.WRITE, required: bool=False, remap_to: str=None):
        """
        重写register_key方法，用于注册key,默认具备可读可写的属性
        """
        super().register_key(key=key, access=access, required=required, remap_to=remap_to)
    
    def require_key(self, key: str):
        """
        强制要求key存在
        """
        self.register_key(key=key, access=Access.WRITE, required=True)

class ReleaseFlowAction(Behaviour, ABC):
    """
    Release Flow 中的最小单元，其本质是一个Behaviour Tree的节点
    继承了py_trees.behaviour.Behaviour的接口
    同时针对我们的Release Flow添加了一些实现的细节
    - setup() 方法用于初始化节点。需要主动调用
    - process() 方法在每次节点开始执行时调用。
    - update() 方法是节点的核心逻辑，返回节点的状态（SUCCESS, FAILURE, RUNNING）。
    - shutdown() 方法用于清理节点。和setup()成对使用
    """
    def __init__(self, name: str, description: str = ""):
        Behaviour.__init__(self, name)
        # blackboard 是所有 flow action 共享的，每个action自己注册自己需要的key
        self.blackboard = self.attach_blackboard_client(name=name)
        self.description = description

    # 重写attach_blackboard_client方法，用于创建ReleaseFlowBlackboard实例
    def attach_blackboard_client(self, name: str=None, namespace: str=None
    ) -> ReleaseFlowBlackboard:
        if name is None:
            count = len(self.blackboards)
            name = self.name if (count == 0) else self.name + "-{}".format(count)
        new_blackboard = ReleaseFlowBlackboard(
            name=name,
            namespace=namespace
        )
        self.blackboards.append(new_blackboard)
        return new_blackboard

    # 子类可以重写setup方法，用于初始化
    def setup(self):
        pass
   
    @abstractmethod
    def update(self):
        pass

    def initialise(self):
        """
        Behaviour 基类中每次tick都会call该函数执行实际的业务逻辑，我们为了方便理解，将名字改为process，
        只要子类实现了process方法，就可以在Release Flow中使用
        """
        try:
            self.process()
        except Exception as e:
            from thirdparty.py_trees.common import Status
            self.status = Status.FAILURE
            log.error(f"Action {self.name} 执行失败: {str(e)}")

    @abstractmethod
    def process(self):
        """
        子类实现process以用于实际的业务逻辑
        """
        pass

def ReleaseFlowActionDecorator(cls):
    """
    装饰器，用于自动生成行为树节点的名称，并自动处理__init__函数
    目的就是为了使得自动生成一个name，而不需要手动去写
    使用方法：
    @ReleaseFlowActionDecorator
    class MyAction(ReleaseFlowAction):
        pass
    """
    # 保存原始的__init__（如果存在的话）
    original_init = cls.__init__ if '__init__' in cls.__dict__ else None
    # 如果不是ReleaseFlowAction的子类，则不进行装饰
    if not issubclass(cls, ReleaseFlowAction):
        return cls

    def new_init(self, name:str=None, description:str=''):
        if name is None:
            name = f"{self.__module__}.{self.__class__.__name__}"
        # 如果原始类有自定义的__init__，则调用它
        if original_init:
            original_init(self, name, description)
        else:
            super(cls, self).__init__(name, description)

    cls.__init__ = new_init
    return cls


class ReleaseFlowBuilder:
    """行为树构建器"""
    def __init__(self):
        self.current_node = None
        self.root = None
        self.node_stack = []
    
    def sequence(self, name: str, description: str = "") -> 'ReleaseFlowBuilder':
        """创建序列节点"""
        if isinstance(name, Enum):
            name = name.value
        node = Sequence(name, description)
        self._add_node(node)
        self.node_stack.append(node)
        return self
    
    def selector(self, name: str, description: str = "") -> 'ReleaseFlowBuilder':
        """创建选择节点"""
        if isinstance(name, Enum):
            name = name.value
        node = Selector(name, description)
        self._add_node(node)
        self.node_stack.append(node)
        return self
    
    def parallel(self, name: str, description: str = "", 
                policy: ParallelPolicy.Base = ParallelPolicy.SuccessOnAll(),
                children: typing.List[Behaviour] = None) -> 'ReleaseFlowBuilder':
        """创建并行节点"""
        if isinstance(name, Enum):
            name = name.value
        node = Parallel(name, policy, children)
        self._add_node(node)
        self.node_stack.append(node)
        return self
    
    def action(self, action: ReleaseFlowAction) -> 'ReleaseFlowBuilder':
        """创建动作节点"""
        if isinstance(action, list):
            for a in action:
                self._add_node(a)
        else:
            self._add_node(action)
        return self
    
    def end(self) -> 'ReleaseFlowBuilder':
        """结束当前复合节点或装饰器节点"""
        if self.node_stack:
            self.node_stack.pop()
        return self
    
    def build(self) -> Behaviour:
        """构建并返回行为树根节点"""
        if not self.root:
            raise ReleaseErr("No nodes added to behavior tree")
            
        # 确保所有节点都已关闭
        if self.node_stack:
            raise ReleaseErr(f"Unclosed nodes: {[node.name for node in self.node_stack]}")
            
        return self.root
    
    def _add_node(self, node: Behaviour):
        """添加节点到当前位置"""
        if not self.root:
            # 第一个节点作为根节点
            self.root = node
            self.current_node = node
            return
            
        if not self.node_stack:
            # 如果没有开放的节点，直接替换根节点
            self.root = node
            self.current_node = node
            return
            
        parent = self.node_stack[-1]
        
        # 将节点添加到父节点
        if isinstance(parent, Composite):
            parent.add_child(node)
        else:
            raise ReleaseErr(f"Parent node {parent.name} is not a Composite")
        # elif isinstance(parent, Decorator):
        #     parent.set_child(node)
        #     # 装饰器只能有一个子节点，所以自动结束
        #     if isinstance(node, (Composite, Decorator)):
        #         # 但如果子节点是复合节点或装饰器，保持它开放
        #         pass
        #     else:
        #         self.node_stack.pop()
    # 添加如下magic函数以用于支持with语句，可简化代码编写，依靠缩进使得层次关系更加清晰
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end()  # 结束序列