"""Tests for explainable denials."""

from pyauthz import (
    Condition,
    Effect,
    PyAuthz,
    Resource,
    Role,
    Subject,
    explain_denial,
)
from pyauthz.models.policy import Policy


class TestExplainDenial:
    def test_suggest_missing_role(self):
        rp = PyAuthz()
        rp.add_role(Role(name="admin", permissions=["*:*"]))
        rp.add_role(Role(name="editor", permissions=["documents:write"]))

        user = Subject(id="bob", roles=["viewer"])
        doc = Resource(id="doc-1", type="documents")
        decision = rp._evaluate(user, "documents:write", doc, {})

        suggestions = explain_denial(rp, decision)
        assert any("admin" in s or "editor" in s for s in suggestions)
        assert any("role" in s.lower() for s in suggestions)

    def test_suggest_owner_condition(self):
        rp = PyAuthz()
        rp.add_role(Role(name="editor", permissions=["documents:write"]))
        rp.add_policy(
            Policy(
                name="owner-edit",
                effect=Effect.ALLOW,
                roles=["editor"],
                permissions=["documents:write"],
                conditions=[
                    Condition(field="resource.owner_id", op="==", value="subject.id"),
                ],
            )
        )

        user = Subject(id="bob", roles=["editor"])
        doc = Resource(id="doc-1", type="documents", owner_id="alice")
        decision = rp._evaluate(user, "documents:write", doc, {})

        suggestions = explain_denial(rp, decision)
        assert any("owner" in s.lower() for s in suggestions)

    def test_allowed_decision(self):
        rp = PyAuthz()
        rp.add_role(Role(name="admin", permissions=["*:*"]))

        user = Subject(id="alice", roles=["admin"])
        doc = Resource(id="doc-1", type="documents")
        decision = rp._evaluate(user, "documents:read", doc, {})

        suggestions = explain_denial(rp, decision)
        assert suggestions == ["Access is already allowed."]

    def test_no_policy_suggestion(self):
        rp = PyAuthz()

        user = Subject(id="bob", roles=[])
        doc = Resource(id="doc-1", type="documents")
        decision = rp._evaluate(user, "documents:write", doc, {})

        suggestions = explain_denial(rp, decision)
        assert any("administrator" in s.lower() or "policy" in s.lower() for s in suggestions)

    def test_environment_condition_suggestion(self):
        rp = PyAuthz()
        rp.add_role(Role(name="editor", permissions=["documents:write"]))
        rp.add_policy(
            Policy(
                name="business-hours",
                effect=Effect.ALLOW,
                roles=["editor"],
                permissions=["documents:write"],
                conditions=[
                    Condition(field="environment.hour", op=">=", value=9),
                    Condition(field="environment.hour", op="<=", value=17),
                ],
            )
        )

        user = Subject(id="alice", roles=["editor"])
        doc = Resource(id="doc-1", type="documents")
        decision = rp._evaluate(user, "documents:write", doc, {"hour": 22})

        suggestions = explain_denial(rp, decision)
        assert any("hour" in s for s in suggestions)
