"""Access control helpers: who may open user/role admin UI and how role groups stay in sync."""

from __future__ import annotations

from collections import defaultdict

from django.contrib.auth.models import Group, Permission

from apps.core.permissions.roles import UserRole


def iilmp_role_values() -> frozenset[str]:
    return frozenset(r.value for r in UserRole)


def sync_user_role_group(user) -> None:
    """
    Keep exactly one Django Group matching `user.role` among IILMP role groups.
    Other group memberships (custom groups) are preserved.
    """
    role_names = iilmp_role_values()
    for g in user.groups.filter(name__in=role_names):
        user.groups.remove(g)
    role = getattr(user, "role", "") or ""
    if role in role_names:
        group, _ = Group.objects.get_or_create(name=role)
        user.groups.add(group)


def can_manage_users(user) -> bool:
    if not user.is_authenticated or not user.is_active:
        return False
    if user.is_superuser:
        return True
    if getattr(user, "role", "") == UserRole.ADMIN:
        return True
    return user.has_perm("core.manage_users")


def can_manage_role_permissions(user) -> bool:
    if not user.is_authenticated or not user.is_active:
        return False
    if user.is_superuser:
        return True
    if getattr(user, "role", "") == UserRole.ADMIN:
        return True
    return user.has_perm("core.manage_role_permissions")


def iilmp_role_groups():
    """Groups created by seed_roles (name == UserRole value)."""
    return Group.objects.filter(name__in=iilmp_role_values()).order_by("name")


def permissions_grouped_by_app():
    """All auth Permission rows grouped by content_type.app_label for matrix UI."""
    qs = (
        Permission.objects.select_related("content_type")
        .order_by("content_type__app_label", "content_type__model", "codename")
        .all()
    )
    by_app: dict[str, list[Permission]] = defaultdict(list)
    for p in qs:
        by_app[p.content_type.app_label].append(p)
    return dict(sorted(by_app.items()))


def user_effective_perm_codes(user) -> set[str]:
    """Human-readable permission strings e.g. core.manage_users."""
    if not user.is_authenticated:
        return set()
    if user.is_superuser:
        return {"*"}
    codes: set[str] = set()
    for p in user.user_permissions.all():
        codes.add(f"{p.content_type.app_label}.{p.codename}")
    for p in Permission.objects.filter(group__user=user).distinct():
        codes.add(f"{p.content_type.app_label}.{p.codename}")
    return codes
