from django.contrib.auth.models import Permission
from django.db import transaction
from django.utils import timezone

from apps.organization.assignment_locks import lock_user
from apps.organization.assignments import UserOrganizationAssignment
from .locks import share_rows
from .models import Role, UserRoleAssignment


def create_role_assignment(*, user, role, organization_assignment, is_active=True):
    return UserRoleAssignment.objects.create(user=user, role=role,
                                            organization_assignment=organization_assignment, is_active=is_active)


def _set_assignment_active(assignment, active):
    with transaction.atomic():
        user_id = UserRoleAssignment.objects.values_list("user_id", flat=True).get(pk=assignment.pk)
        lock_user(user_id)
        record = UserRoleAssignment.objects.get(pk=assignment.pk)
        share_rows(UserOrganizationAssignment, [record.organization_assignment_id])
        share_rows(Role, [record.role_id])
        record.refresh_from_db()
        record.is_active = active
        record.save(update_fields=["is_active"])
        return record


def deactivate_role_assignment(*, assignment):
    return _set_assignment_active(assignment, False)


def reactivate_role_assignment(*, assignment):
    return _set_assignment_active(assignment, True)


def deactivate_role(*, role):
    with transaction.atomic():
        record = Role.objects.select_for_update().get(pk=role.pk)
        record.user_assignments.active().update(is_active=False, updated_at=timezone.now())
        record.is_active = False
        record.save(update_fields=["is_active"])
        return record


def reactivate_role(*, role):
    with transaction.atomic():
        record = Role.objects.select_for_update().get(pk=role.pk)
        record.is_active = True
        record.save(update_fields=["is_active"])
        return record


def set_role_permissions(*, role, permissions):
    """Replace a role's existing Django Permission membership atomically."""
    permissions = list(permissions)
    if any(not isinstance(item, Permission) or item.pk is None for item in permissions):
        raise ValueError("Supply saved Django Permission objects.")
    with transaction.atomic():
        record = Role.objects.select_for_update().get(pk=role.pk)
        ids = {item.pk for item in permissions}
        existing = list(Permission.objects.filter(pk__in=ids))
        if len(existing) != len(ids):
            raise ValueError("All permissions must exist in the database.")
        record.permissions.set(existing)
        record.save(update_fields=["updated_at"])
        return record
