"""
Parser unit tests

Tests the Cedar text → PolicyRule conversion using the official Cedar engine.
These tests demonstrate how a client like highflame-authz would use the parser.
"""

import pytest
from highflame_policy import parse_cedar_to_rules, ParseResult


def test_parse_simple_permit():
    """Test parsing a simple permit policy."""
    cedar_text = '''
        @id("allow-read-files")
        permit(
            principal is User,
            action == Action::"read_file",
            resource is FilePath
        );
    '''

    result = parse_cedar_to_rules(cedar_text)

    assert len(result.errors) == 0
    assert len(result.rules) == 1
    assert len(result.unstructured) == 0

    rule = result.rules[0]
    assert rule["id"] == "allow-read-files"
    assert rule["effect"] == "permit"
    assert rule["principal"]["type"] == "User"
    assert rule["action"] == "read_file"
    assert rule["resource"]["type"] == "FilePath"
    assert rule["enabled"] is True


def test_parse_with_conditions():
    """Test parsing a policy with when conditions."""
    cedar_text = '''
        @id("block-high-risk")
        forbid(
            principal,
            action == Action::"execute_tool",
            resource
        )
        when {
            context.threat_level == "high"
        };
    '''

    result = parse_cedar_to_rules(cedar_text)

    assert len(result.errors) == 0
    assert len(result.rules) == 1

    rule = result.rules[0]
    assert rule["id"] == "block-high-risk"
    assert rule["effect"] == "forbid"
    assert rule["action"] == "execute_tool"

    # Check condition was parsed (either as structured or raw)
    conditions = rule.get("conditions", [])
    raw_condition = rule.get("rawCondition")

    if len(conditions) > 0:
        assert conditions[0]["field"] == "threat_level"
        assert conditions[0]["operator"] == "eq"
        assert conditions[0]["value"] == "high"
    else:
        assert raw_condition is not None


def test_parse_invalid_syntax():
    """Test that invalid Cedar syntax returns errors."""
    invalid_cedar = '''
        permit(
            principal is User
            // missing comma and rest of policy
    '''

    result = parse_cedar_to_rules(invalid_cedar)

    assert len(result.errors) > 0


def test_parse_multiple_policies():
    """Test parsing multiple policies."""
    cedar_text = '''
        @id("rule-1")
        permit(principal, action == Action::"read", resource);

        @id("rule-2")
        forbid(principal, action == Action::"delete", resource);
    '''

    result = parse_cedar_to_rules(cedar_text)

    assert len(result.errors) == 0
    assert len(result.rules) == 2
    assert result.rules[0]["effect"] == "permit"
    assert result.rules[1]["effect"] == "forbid"


def test_unless_clause_in_unstructured():
    """Test that policies with unless clauses go to unstructured."""
    cedar_text = '''
        permit(principal, action, resource)
        unless {
            context.is_blocked == true
        };
    '''

    result = parse_cedar_to_rules(cedar_text)

    # Unless clauses can't be represented as PolicyRule
    assert len(result.rules) == 0
    assert len(result.unstructured) > 0
