"""Sandboxed templating and condition evaluation."""

from __future__ import annotations

import pytest
from legate.workflow.templating import (
    ExpressionError,
    evaluate_condition,
    render_value,
    resolve_path,
)

CONTEXT = {
    "trigger": {"body": {"priority": "high", "count": 5}},
    "a1": {"output": {"priority": "high", "tags": ["urgent", "billing"]}},
}


def test_resolve_path_nested_and_missing():
    assert resolve_path("trigger.body.priority", CONTEXT) == "high"
    assert resolve_path("a1.output.tags.0", CONTEXT) == "urgent"
    assert resolve_path("trigger.body.nope", CONTEXT) is None


def test_render_value_preserves_type_for_lone_reference():
    assert render_value("{{ trigger.body.count }}", CONTEXT) == 5
    assert render_value("{{ a1.output.tags }}", CONTEXT) == ["urgent", "billing"]


def test_render_value_interpolates_and_walks_structures():
    assert render_value("priority is {{ a1.output.priority }}", CONTEXT) == "priority is high"
    rendered = render_value(
        {"msg": "count={{ trigger.body.count }}", "items": ["{{ a1.output.priority }}"]}, CONTEXT
    )
    assert rendered == {"msg": "count=5", "items": ["high"]}


def test_evaluate_condition_comparisons_and_membership():
    assert evaluate_condition("{{ a1.output.priority }} == 'high'", CONTEXT) is True
    assert evaluate_condition("{{ trigger.body.count }} > 3", CONTEXT) is True
    assert evaluate_condition("{{ trigger.body.count }} < 3", CONTEXT) is False
    assert evaluate_condition("'urgent' in {{ a1.output.tags }}", CONTEXT) is True
    assert (
        evaluate_condition(
            "{{ a1.output.priority }} == 'high' and {{ trigger.body.count }} >= 5", CONTEXT
        )
        is True
    )


def test_evaluate_condition_rejects_code_execution():
    # No calls, attribute access, or arbitrary names are permitted.
    for expr in ["__import__('os').system('x')", "open('f')", "trigger.body"]:
        with pytest.raises(ExpressionError):
            evaluate_condition(expr, CONTEXT)
