from pathlib import Path
import pytest
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from thirdparty.py_trees.trees import BehaviourTree
from core.behavior_tree import ReleaseFlowActionDecorator, ReleaseFlowBuilder, ReleaseFlowAction
from thirdparty.py_trees.common import Status, Access
from core.logger import get_logger

log = get_logger()

class ActionTest(ReleaseFlowAction):
    """测试用的Action节点"""
    def __init__(self, name: str, return_status: Status, description: str = ""):
        super().__init__(name, description)
        self.return_status = return_status
        self.process_called = False
        self.setup_called = False
        self.shutdown_called = False

    def setup(self):
        self.setup_called = True
        log.info(f"setup: {self.name}")

    def process(self):
        self.process_called = True
        self.status = self.return_status
        log.info(f"process: {self.name}, status: {self.status}")

    def update(self):
        return self.status

    def shutdown(self):
        self.shutdown_called = True

class ActionTestBlackboard(ReleaseFlowAction):
    """测试Blackboard功能的Action节点"""
    def __init__(self, name: str, description: str = ""):
        super().__init__(name, description)
        self.blackboard.register_key("test_key", access=Access.WRITE)
        self.blackboard.register_key("read_only_key", access=Access.READ)

    def process(self):
        self.status = Status.SUCCESS
        log.info(f"process: {self.name}, status: {self.status}, test_key: {self.blackboard.test_key}")

    def update(self):
        return self.status

class ActionTestBlackboard1(ReleaseFlowAction):
    """测试Blackboard功能的Action节点"""
    def __init__(self, name: str, description: str = ""):
        super().__init__(name, description)
        self.blackboard.require_key("test_key")

    def process(self):
        self.status = Status.SUCCESS
        log.info(f"process: {self.name}, status: {self.status}, test_key: {self.blackboard.test_key}")

    def update(self):
        return self.status 

@pytest.fixture
def builder():
    """创建ReleaseFlowBuilder实例的fixture"""
    return ReleaseFlowBuilder()

def test_single_action():
    """测试单个Action节点的执行"""
    action = ActionTest("test_action", Status.SUCCESS)
    action.setup()
    assert action.setup_called
    
    action.tick_once()
    assert action.process_called
    assert action.status == Status.SUCCESS
    
    action.shutdown()
    assert action.shutdown_called

def test_sequence(builder):
    """测试Sequence节点的执行"""
    success_action = ActionTest("success_action", Status.SUCCESS)
    failure_action = ActionTest("failure_action", Status.FAILURE)

    with builder.sequence("test_sequence") as b:
        b.action(success_action)
        b.action(failure_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()

    assert failure_action.process_called
    assert flow.status == Status.FAILURE
    assert success_action.process_called

def test_selector(builder):
    """测试Selector节点的执行"""
    failure_action = ActionTest("failure_action", Status.FAILURE)
    success_action = ActionTest("success_action", Status.SUCCESS)
    
    with builder.selector("test_selector") as b:
        b.action(failure_action)
        b.action(success_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.SUCCESS
    assert failure_action.process_called
    assert success_action.process_called

def test_blackboard():
    """测试Blackboard功能"""
    action = ActionTestBlackboard("test_blackboard")
    action1 = ActionTestBlackboard1("test_blackboard_read")
    
    # 测试写入权限
    action.blackboard.test_key = "test_value"
    # 测试共享
    assert action1.blackboard.test_key == "test_value"
    
    # 测试只读权限
    with pytest.raises(AttributeError):
        action.blackboard.read_only_key = "new_value"
    
    # 测试必需key
    with pytest.raises(AttributeError):
        _ = action.blackboard.required_key

def test_parallel(builder):
    """测试Parallel节点的执行"""
    success_action1 = ActionTest("success_action1", Status.SUCCESS)
    success_action2 = ActionTest("success_action2", Status.SUCCESS)
    failure_action = ActionTest("failure_action", Status.FAILURE)
    
    with builder.parallel("test_parallel") as b:
        b.action(success_action1)
        b.action(success_action2)
        b.action(failure_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.FAILURE
    assert success_action1.process_called
    assert success_action2.process_called
    assert failure_action.process_called

def test_nested_behavior_tree(builder):
    """测试嵌套的行为树结构"""
    success_action1 = ActionTest("success_action1", Status.SUCCESS)
    success_action2 = ActionTest("success_action2", Status.SUCCESS)
    failure_action = ActionTest("failure_action", Status.FAILURE)
    
    with builder.sequence("root_sequence") as b:
        with b.selector("nested_selector") as s:
            s.action(failure_action)
            s.action(success_action1)
        b.action(success_action2)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.SUCCESS
    assert failure_action.process_called
    assert success_action1.process_called
    assert success_action2.process_called

def test_parallel_success_on_all(builder):
    """测试并行节点SuccessOnAll策略"""
    success_action1 = ActionTest("success_action1", Status.SUCCESS)
    success_action2 = ActionTest("success_action2", Status.SUCCESS)
    success_action3 = ActionTest("success_action3", Status.SUCCESS)
    
    with builder.parallel("test_parallel_success_on_all") as b:
        b.action(success_action1)
        b.action(success_action2)
        b.action(success_action3)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.SUCCESS
    assert success_action1.process_called
    assert success_action2.process_called
    assert success_action3.process_called

def test_parallel_success_on_one(builder):
    """测试并行节点SuccessOnOne策略"""
    from thirdparty.py_trees.common import ParallelPolicy
    
    running_action1 = ActionTest("running_action1", Status.RUNNING)
    success_action = ActionTest("success_action", Status.SUCCESS)
    running_action2 = ActionTest("running_action2", Status.RUNNING)
    
    with builder.parallel("test_parallel_success_on_one", 
                         policy=ParallelPolicy.SuccessOnOne()) as b:
        b.action(running_action1)
        b.action(success_action)
        b.action(running_action2)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.SUCCESS
    assert running_action1.process_called
    assert success_action.process_called
    assert running_action2.process_called

def test_multiple_executions(builder):
    """测试行为树的多次执行"""
    action1 = ActionTest("action1", Status.SUCCESS)
    action2 = ActionTest("action2", Status.SUCCESS)
    
    with builder.sequence("test_multiple_executions") as b:
        b.action(action1)
        b.action(action2)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    
    # 第一次执行
    tree.tick()
    assert flow.status == Status.SUCCESS
    assert action1.process_called
    assert action2.process_called
    
    # 重置状态
    action1.process_called = False
    action2.process_called = False
    
    # 第二次执行
    tree.tick()
    assert flow.status == Status.SUCCESS
    assert action1.process_called
    assert action2.process_called

def test_error_handling(builder):
    """测试行为树的错误处理"""
    # 测试空的行为树
    with pytest.raises(Exception) as excinfo:
        builder.build()
    assert "No nodes added to behavior tree" in str(excinfo.value)
    # 测试未闭合的节点
    with pytest.raises(Exception) as excinfo:
        with builder.sequence("unclosed_sequence") as b:
            b.action(ActionTest("action", Status.SUCCESS))
            b.action(ActionTest("action", Status.SUCCESS))
            # 不调用end()或使用with语句的__exit__
            builder.build()
    assert "Unclosed nodes" in str(excinfo.value)
    
    
    

class ActionWithError(ReleaseFlowAction):
    """测试异常处理的Action节点"""
    def __init__(self, name: str, description: str = ""):
        super().__init__(name, description)
        self.process_called = False
    
    def process(self):
        self.process_called = True
        raise Exception("测试异常")
    
    def update(self):
        return Status.FAILURE

def test_action_exception_handling(builder):
    """测试Action节点异常处理"""
    error_action = ActionWithError("error_action")
    
    with builder.sequence("test_error_handling") as b:
        b.action(error_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    
    # 执行时应该捕获异常并返回FAILURE状态
    tree.tick()
    assert error_action.process_called
    assert flow.status == Status.FAILURE

def test_decorator():
    """测试ReleaseFlowActionDecorator装饰器"""
    @ReleaseFlowActionDecorator
    class DecoratedAction(ReleaseFlowAction):
        def process(self):
            self.status = Status.SUCCESS
        
        def update(self):
            return self.status

    # 测试自动生成名称
    action1 = DecoratedAction()
    assert action1.name == f"{Path(__file__).stem}.DecoratedAction"

    # 测试自定义名称
    action2 = DecoratedAction(name="custom_name")
    assert action2.name == "custom_name"

    # 测试功能
    action2.setup()
    action2.tick_once()
    assert action2.status == Status.SUCCESS

def test_complex_behavior_tree(builder):
    """测试复杂的行为树结构"""
    success_action1 = ActionTest("success_action1", Status.SUCCESS)
    success_action2 = ActionTest("success_action2", Status.SUCCESS)
    failure_action1 = ActionTest("failure_action1", Status.FAILURE)
    success_action3 = ActionTest("success_action3", Status.SUCCESS)
    
    with builder.sequence("root") as b:
        with b.parallel("parallel_group") as p:
            p.action(success_action1)
            p.action(success_action2)
        with b.selector("selector_group") as s:
            s.action(failure_action1)
            s.action(success_action3)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    tree.tick()
    
    assert flow.status == Status.SUCCESS
    assert success_action1.process_called
    assert success_action2.process_called
    assert failure_action1.process_called
    assert success_action3.process_called

def test_blackboard_advanced():
    """测试Blackboard的高级功能"""
    class ActionWrite(ReleaseFlowAction):
        def __init__(self, name: str, description: str = ""):
            super().__init__(name, description)
            self.blackboard.register_key("counter", access=Access.WRITE)
            self.blackboard.counter = 0
        
        def process(self):
            self.blackboard.counter += 1
            self.status = Status.SUCCESS
        
        def update(self):
            return self.status
    
    class ActionRead(ReleaseFlowAction):
        def __init__(self, name: str, description: str = ""):
            super().__init__(name, description)
            self.blackboard.register_key("counter", access=Access.READ)
            self.value = 0
        
        def process(self):
            self.value = self.blackboard.counter
            self.status = Status.SUCCESS
        
        def update(self):
            return self.status
    
    # 创建动作节点
    write_action = ActionWrite("write_action")
    read_action = ActionRead("read_action")
    
    # 设置初始值
    write_action.blackboard.counter = 10
    
    # 测试读取
    assert read_action.blackboard.counter == 10
    
    # 测试写入
    write_action.blackboard.counter = 20
    assert read_action.blackboard.counter == 20
    
    # 测试只读权限
    with pytest.raises(AttributeError):
        read_action.blackboard.counter = 30

def test_action_exception_handling_with_sequence(builder):
    """测试Action节点异常处理后行为树继续执行的能力"""
    error_action = ActionWithError("error_action")
    success_action = ActionTest("success_action", Status.SUCCESS)
    
    with builder.sequence("test_error_handling_sequence") as b:
        b.action(error_action)
        b.action(success_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    
    # 执行时应该捕获异常并返回FAILURE状态，但不会中断行为树的执行
    tree.tick()
    
    # 验证error_action被标记为已处理
    assert error_action.process_called
    
    # 验证序列节点状态为FAILURE（因为第一个节点失败）
    assert flow.status == Status.FAILURE
    
    # 验证success_action没有被执行（因为序列节点在第一个节点失败后停止）
    assert not success_action.process_called

def test_action_exception_handling_with_selector(builder):
    """测试Action节点异常处理后选择器继续尝试其他节点"""
    error_action = ActionWithError("error_action")
    success_action = ActionTest("success_action", Status.SUCCESS)
    
    with builder.selector("test_error_handling_selector") as b:
        b.action(error_action)
        b.action(success_action)
    
    flow = builder.build()
    tree = BehaviourTree(root=flow)
    tree.setup()
    
    # 执行时应该捕获异常并继续尝试下一个节点
    tree.tick()
    
    # 验证error_action被标记为已处理
    assert error_action.process_called
    
    # 验证success_action被执行
    assert success_action.process_called
    
    # 验证选择器节点状态为SUCCESS（因为第二个节点成功）
    assert flow.status == Status.SUCCESS
