from __future__ import annotations

import pytest

from simorgh.apps.iam.engine import is_allowed
from simorgh.apps.iam.models import Policy
from simorgh.apps.memberships.services import (
    active_memberships_for,
    assignable_node_ids,
)
from simorgh.core.context import RequestContext


def _ctx(user, tenant, memberships, perms, org_ids):
    return RequestContext(
        actor=user,
        tenant=tenant,
        memberships=tuple(memberships),
        permissions=frozenset(perms),
        org_node_ids=frozenset(org_ids),
    )


@pytest.mark.django_db
def test_membership_resolves_assignable_descendants(alice, alice_membership, acme_tree):
    memberships = list(active_memberships_for(alice.pk, alice_membership.tenant_id))
    ids = assignable_node_ids(memberships)
    # Alice is on EU → she can act on EU and DE, not on HQ or US.
    assert ids == {acme_tree["eu"].pk, acme_tree["de"].pk}


@pytest.mark.django_db
def test_rbac_grants_when_codename_present(alice, tenant_acme, alice_membership, perms):
    ctx = _ctx(alice, tenant_acme, [alice_membership], {"organizations.node.view"}, set())
    assert is_allowed(ctx, "organizations.node.view") is True
    assert is_allowed(ctx, "organizations.node.manage") is False


@pytest.mark.django_db
def test_unauthenticated_is_always_denied(tenant_acme):
    ctx = _ctx(None, tenant_acme, [], set(), set())
    assert is_allowed(ctx, "tenants.tenant.view") is False


@pytest.mark.django_db
def test_superuser_bypasses_rbac(db, tenant_acme):
    from simorgh.apps.accounts.models import User

    su = User.objects.create_superuser("+989000000099", password="x", email="root@example.com")
    ctx = _ctx(su, tenant_acme, [], set(), set())
    assert is_allowed(ctx, "anything.at.all") is True


@pytest.mark.django_db
def test_abac_policy_blocks_when_condition_fails(
    alice, tenant_acme, alice_membership, role_viewer, perms
):
    perm = perms["organizations.node.view"]
    Policy.objects.create(
        role=role_viewer,
        permission=perm,
        name="only-eu-region",
        conditions={"==": [{"attr": "resource.region"}, "EU"]},
    )

    class Resource:
        region = "US"

    ctx = _ctx(alice, tenant_acme, [alice_membership], {perm.codename}, set())
    assert is_allowed(ctx, perm.codename, resource=Resource()) is False

    Resource.region = "EU"
    assert is_allowed(ctx, perm.codename, resource=Resource()) is True


@pytest.mark.django_db
def test_role_inheritance_collects_parent_permissions(tenant_acme, perms):
    from simorgh.apps.iam.engine import resolved_permissions
    from simorgh.apps.iam.models import Role

    parent = Role.objects.create(tenant=tenant_acme, code="parent", name="Parent")
    parent.permissions.set([perms["tenants.tenant.view"]])
    child = Role.objects.create(tenant=tenant_acme, code="child", name="Child", parent_role=parent)
    child.permissions.set([perms["organizations.node.view"]])

    codes = resolved_permissions(child)
    assert codes == {"tenants.tenant.view", "organizations.node.view"}
