import tempfile
from pathlib import Path

from brox.policy.engine import evaluate_policy, scope_matches


class TestScopeMatches:
    def test_exact_match(self):
        assert scope_matches("/data/**", "/data/**") is True

    def test_root_wildcard_matches_all(self):
        assert scope_matches("/etc/**", "/**") is True
        assert scope_matches("/data/**", "/**") is True
        assert scope_matches("anything/**", "/**") is True

    def test_prefix_match(self):
        assert scope_matches("/etc/passwd/**", "/etc/**") is True
        assert scope_matches("/var/log/**", "/var/**") is True

    def test_no_match(self):
        assert scope_matches("/etc/**", "/var/**") is False
        assert scope_matches("/data/**", "/logs/**") is False


class TestEvaluatePolicy:
    def test_block_action_fails_policy(self):
        policy_content = """
version: 1
rules:
  - id: block-shell
    when:
      capability_added: "exec.shell"
    action: block
    message: "Shell execution blocked"
"""

        diff_data = {
            "capabilities": {
                "added": [
                    {
                        "capability": "exec.shell",
                        "scope": "*",
                        "asset": "mcp_server:shell",
                        "evidence": ["mcp.json:10"],
                    }
                ]
            },
            "assets": {"added": [], "removed": [], "changed": []},
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(policy_content)
            policy_path = f.name

        try:
            result = evaluate_policy(diff_data, policy_path)

            assert result["decision"] == "block"
            assert len(result["triggered_rules"]) == 1
            assert result["triggered_rules"][0]["id"] == "block-shell"
        finally:
            Path(policy_path).unlink()

    def test_warn_action_passes_with_warning(self):
        policy_content = """
version: 1
rules:
  - id: warn-egress
    when:
      capability_added: "network.egress"
    action: warn
    message: "New egress domain"
"""

        diff_data = {
            "capabilities": {
                "added": [
                    {
                        "capability": "network.egress",
                        "scope": "api.example.com",
                        "asset": "llm_provider:example",
                        "evidence": ["app.py:10"],
                    }
                ]
            },
            "assets": {"added": [], "removed": [], "changed": []},
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(policy_content)
            policy_path = f.name

        try:
            result = evaluate_policy(diff_data, policy_path)

            assert result["decision"] == "warn"
            assert len(result["triggered_rules"]) == 1
        finally:
            Path(policy_path).unlink()

    def test_scope_matches_any_condition(self):
        policy_content = """
version: 1
rules:
  - id: block-sensitive-fs
    when:
      capability_added: "filesystem.write"
      scope_matches_any:
        - "/**"
        - "/etc/**"
    action: block
    message: "Sensitive filesystem write"
"""

        diff_data_matches = {
            "capabilities": {
                "added": [
                    {
                        "capability": "filesystem.write",
                        "scope": "/etc/**",
                        "asset": "mcp_server:fs",
                        "evidence": ["mcp.json:10"],
                    }
                ]
            },
            "assets": {"added": [], "removed": [], "changed": []},
        }

        diff_data_no_match = {
            "capabilities": {
                "added": [
                    {
                        "capability": "filesystem.write",
                        "scope": "/data/**",
                        "asset": "mcp_server:fs",
                        "evidence": ["mcp.json:10"],
                    }
                ]
            },
            "assets": {"added": [], "removed": [], "changed": []},
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(policy_content)
            policy_path = f.name

        try:
            result1 = evaluate_policy(diff_data_matches, policy_path)
            assert result1["decision"] == "block"

            result2 = evaluate_policy(diff_data_no_match, policy_path)
            assert result2["decision"] == "pass"
        finally:
            Path(policy_path).unlink()

    def test_no_rules_triggered_passes(self):
        policy_content = """
version: 1
rules:
  - id: block-shell
    when:
      capability_added: "exec.shell"
    action: block
    message: "Shell blocked"
"""

        diff_data = {
            "capabilities": {"added": []},
            "assets": {"added": [], "removed": [], "changed": []},
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(policy_content)
            policy_path = f.name

        try:
            result = evaluate_policy(diff_data, policy_path)
            assert result["decision"] == "pass"
            assert len(result["triggered_rules"]) == 0
        finally:
            Path(policy_path).unlink()
