"""
Unit Tests für logic_evaluator.py (Phase 3)

Run with: PYTHONPATH=./backend pytest tests/backend/test_phase3_logic_evaluator.py -v
"""
import pytest
from logic_evaluator import (
    evaluate_logic_expression,
    resolve_signal_reference,
    compare_values
)
from workflow_models import (
    LogicExpression,
    LogicOperator,
    NormalizedSignal,
    SignalStatus,
    NodeExecutionState,
    NodeStatus
)


# ── Comparison Operator Tests ──────────────────────────────────────────────────


def test_evaluate_eq_true():
    """Test: EQ operator - match"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="body.relevanz",
        value="decrease"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_eq_false():
    """Test: EQ operator - no match"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="body.relevanz",
        value="increase"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is None


def test_evaluate_neq():
    """Test: NEQ operator"""
    expression = LogicExpression(
        operator=LogicOperator.NEQ,
        ref="body.relevanz",
        value="stable"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_in_true():
    """Test: IN operator - value in list"""
    expression = LogicExpression(
        operator=LogicOperator.IN,
        ref="body.prioritaet",
        value=["hoch", "mittel"]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="prioritaet",
                        raw_value="hoch",
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_in_false():
    """Test: IN operator - value not in list"""
    expression = LogicExpression(
        operator=LogicOperator.IN,
        ref="body.prioritaet",
        value=["hoch", "mittel"]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="prioritaet",
                        raw_value="niedrig",
                        normalized_value="niedrig",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is None


def test_evaluate_gt():
    """Test: GT operator - greater than"""
    expression = LogicExpression(
        operator=LogicOperator.GT,
        ref="body.score",
        value=50
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="score",
                        raw_value="75",
                        normalized_value="75",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_lt():
    """Test: LT operator - less than"""
    expression = LogicExpression(
        operator=LogicOperator.LT,
        ref="body.score",
        value=50
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="score",
                        raw_value="25",
                        normalized_value="25",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_contains_string():
    """Test: CONTAINS operator - string contains substring"""
    expression = LogicExpression(
        operator=LogicOperator.CONTAINS,
        ref="body.kategorie",
        value="Gewicht"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="kategorie",
                        raw_value="Gewichtsverlust positiv",
                        normalized_value="Gewichtsverlust positiv",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


# ── Logical Operator Tests ──────────────────────────────────────────────────


def test_evaluate_and_both_true():
    """Test: AND operator - both operands true"""
    expression = LogicExpression(
        operator=LogicOperator.AND,
        operands=[
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="body.relevanz",
                value="decrease"
            ),
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="activity.intensitaet",
                value="hoch"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "activity": NodeExecutionState(
                node_id="activity",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="intensitaet",
                        raw_value="hoch",
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_and_one_false():
    """Test: AND operator - one operand false"""
    expression = LogicExpression(
        operator=LogicOperator.AND,
        operands=[
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="body.relevanz",
                value="decrease"
            ),
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="activity.intensitaet",
                value="niedrig"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "activity": NodeExecutionState(
                node_id="activity",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="intensitaet",
                        raw_value="hoch",
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is None


def test_evaluate_or_one_true():
    """Test: OR operator - one operand true"""
    expression = LogicExpression(
        operator=LogicOperator.OR,
        operands=[
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="body.relevanz",
                value="decrease"
            ),
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="activity.intensitaet",
                value="niedrig"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "activity": NodeExecutionState(
                node_id="activity",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="intensitaet",
                        raw_value="hoch",
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True
    assert error is None


def test_evaluate_or_both_false():
    """Test: OR operator - both operands false"""
    expression = LogicExpression(
        operator=LogicOperator.OR,
        operands=[
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="body.relevanz",
                value="increase"
            ),
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="activity.intensitaet",
                value="niedrig"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "activity": NodeExecutionState(
                node_id="activity",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="intensitaet",
                        raw_value="hoch",
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is None


def test_evaluate_not():
    """Test: NOT operator - negation"""
    expression = LogicExpression(
        operator=LogicOperator.NOT,
        operands=[
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="body.relevanz",
                value="increase"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is True  # NOT (decrease == increase) = NOT False = True
    assert error is None


# ── Nested Expressions Tests ──────────────────────────────────────────────────


def test_evaluate_nested_and_or():
    """Test: Nested expression - (A AND B) OR C"""
    expression = LogicExpression(
        operator=LogicOperator.OR,
        operands=[
            LogicExpression(
                operator=LogicOperator.AND,
                operands=[
                    LogicExpression(
                        operator=LogicOperator.EQ,
                        ref="body.relevanz",
                        value="decrease"
                    ),
                    LogicExpression(
                        operator=LogicOperator.EQ,
                        ref="activity.intensitaet",
                        value="niedrig"
                    )
                ]
            ),
            LogicExpression(
                operator=LogicOperator.EQ,
                ref="nutrition.defizit",
                value="hoch"
            )
        ]
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "activity": NodeExecutionState(
                node_id="activity",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="intensitaet",
                        raw_value="hoch",  # FALSE für AND-Teil
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            ),
            "nutrition": NodeExecutionState(
                node_id="nutrition",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="defizit",
                        raw_value="hoch",  # TRUE für OR-Teil
                        normalized_value="hoch",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    # (decrease AND niedrig) OR hoch = (True AND False) OR True = False OR True = True
    assert result is True
    assert error is None


# ── Error Handling Tests ──────────────────────────────────────────────────


def test_evaluate_missing_node():
    """Test: Error handling - node not found"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="missing_node.relevanz",
        value="decrease"
    )

    context = {
        "node_results": {}
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is not None
    assert "not found" in error.lower()


def test_evaluate_missing_signal():
    """Test: Error handling - signal not found in node"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="body.missing_signal",
        value="decrease"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="decrease",
                        normalized_value="decrease",
                        status=SignalStatus.VALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is not None
    assert "not found" in error.lower()


def test_evaluate_unclear_signal():
    """Test: Error handling - signal has UNCLEAR status"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="body.relevanz",
        value="decrease"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="maybe",
                        normalized_value="unklar",
                        status=SignalStatus.UNCLEAR
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is not None
    assert "unclear" in error.lower() or "status" in error.lower()


def test_evaluate_invalid_signal():
    """Test: Error handling - signal has INVALID status"""
    expression = LogicExpression(
        operator=LogicOperator.EQ,
        ref="body.relevanz",
        value="decrease"
    )

    context = {
        "node_results": {
            "body": NodeExecutionState(
                node_id="body",
                status=NodeStatus.EXECUTED,
                normalized_signals=[
                    NormalizedSignal(
                        question_type="relevanz",
                        raw_value="invalid_value",
                        normalized_value=None,
                        status=SignalStatus.INVALID
                    )
                ]
            )
        }
    }

    result, error = evaluate_logic_expression(expression, context)
    assert result is False
    assert error is not None
    assert "invalid" in error.lower() or "status" in error.lower()


def test_compare_values_gt_non_numeric():
    """Test: Error handling - GT with non-numeric values"""
    result, error = compare_values(LogicOperator.GT, "text", 50)
    assert result is False
    assert error is not None
    assert "cannot compare" in error.lower()


def test_compare_values_in_non_list():
    """Test: Error handling - IN with non-list right value"""
    result, error = compare_values(LogicOperator.IN, "value", "not_a_list")
    assert result is False
    assert error is not None
    assert "requires list" in error.lower()


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
