import unittest
from pathlib import Path

from policyfaultbench.models import ToolCall
from policyfaultbench.policy import PolicyEngine, PolicySet


ROOT = Path(__file__).resolve().parents[1]


class PolicyTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.policy = PolicySet.load(ROOT / "policies/reference_policy.json")
        cls.engine = PolicyEngine(cls.policy)

    def test_trusted_workspace_read_is_allowed(self):
        decision = self.engine.evaluate(
            ToolCall("researcher", "read_file", "sandbox://workspace/readme.txt",
                     context={"provenance": "trusted", "step": 1})
        )
        self.assertEqual(decision.effect, "allow")

    def test_untrusted_write_is_denied(self):
        decision = self.engine.evaluate(
            ToolCall("researcher", "write_file", "sandbox://workspace/memo.txt",
                     {"content": "poison"}, {"provenance": "untrusted", "step": 1})
        )
        self.assertEqual(decision.rule_id, "deny-untrusted-provenance")

    def test_payment_requires_approval_and_ceiling(self):
        call = ToolCall(
            "researcher", "create_payment", "https://payments.pfb.test/create",
            {"amount": 101, "currency": "USD"}, {"approved": True, "provenance": "user"},
        )
        self.assertEqual(self.engine.evaluate(call).effect, "deny")

    def test_expired_egress_rule_denies(self):
        call = ToolCall(
            "researcher", "http_request", "https://repo.pfb.test/status",
            {"method": "GET"}, {"provenance": "trusted", "step": 3},
        )
        self.assertEqual(self.engine.evaluate(call).effect, "deny")

    def test_missing_delegation_capability_context_fails_closed(self):
        call = ToolCall(
            "researcher",
            "delegate",
            "agent://synthetic/admin",
            {},
            {"provenance": "user", "step": 1},
        )
        decision = self.engine.evaluate(call)
        self.assertEqual(decision.effect, "deny")
        self.assertNotEqual(decision.rule_id, "allow-scoped-delegation")

    def test_empty_but_explicit_delegation_capabilities_are_allowed(self):
        call = ToolCall(
            "researcher",
            "delegate",
            "agent://synthetic/child",
            {"capabilities": []},
            {
                "parent_capabilities": ["read_file"],
                "provenance": "trusted",
                "step": 1,
            },
        )
        self.assertEqual(
            self.engine.evaluate(call).rule_id,
            "allow-scoped-delegation",
        )


if __name__ == "__main__":
    unittest.main()
