from typing import Any, Callable

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


def add_permission_to_groups_based_on_existing_permission(
    codename: str, model: str, app_label: str, new_codename: str, new_name: str
) -> Callable[[Any, Any], None]:
    """
    Creates the new permission given by new_codename and new_name to all groups,
    that have the base permission. This base permission is given by codename, model
    and app_label. The new permission will have the same content type as the base
    permission. The migration just runs, if the base permission and content type do
    exist, so this does not run for a fresh database.
    """

    def function(apps: Any, schema_editor: Any) -> None:
        content_type = ContentType.objects.filter(model=model, app_label=app_label)
        base_perm = Permission.objects.filter(
            codename=codename, content_type__in=content_type
        )

        if len(base_perm) == 1 and len(content_type) == 1:
            # get the actual content type and base permission
            base_perm = base_perm.get()
            content_type = content_type.get()

            # Save groups. list() is necessary to evaluate the database query right now.
            groups = list(base_perm.group_set.all())

            # Create new permission
            perm = Permission.objects.create(
                codename=new_codename, name=new_name, content_type=content_type
            )

            # Add this permission to all groups
            for group in groups:
                group.permissions.add(perm)
                group.save()

    return function