# Generated by Django 5.1.9 on 2025-05-14 11:15

from django.apps.registry import Apps, apps as global_apps
from django.db import migrations
from django.contrib.contenttypes.management import create_contenttypes
from django.contrib.auth.management import create_permissions
from django.db.backends.base.schema import BaseDatabaseSchemaEditor


def migrate_authenticated_session_permissions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    """Migrate permissions from OldAuthenticatedSession to AuthenticatedSession"""
    db_alias = schema_editor.connection.alias

    # `apps` here is just an instance of `django.db.migrations.state.AppConfigStub`, we need the
    # real config for creating permissions and content types
    authentik_core_config = global_apps.get_app_config("authentik_core")
    # These are only ran by django after all migrations, but we need them right now.
    # `global_apps` is needed,
    create_permissions(authentik_core_config, using=db_alias, verbosity=1)
    create_contenttypes(authentik_core_config, using=db_alias, verbosity=1)

    # But from now on, this is just a regular migration, so use `apps`
    Permission = apps.get_model("auth", "Permission")
    ContentType = apps.get_model("contenttypes", "ContentType")

    try:
        old_ct = ContentType.objects.using(db_alias).get(
            app_label="authentik_core", model="oldauthenticatedsession"
        )
        new_ct = ContentType.objects.using(db_alias).get(
            app_label="authentik_core", model="authenticatedsession"
        )
    except ContentType.DoesNotExist:
        # This should exist at this point, but if not, let's cut our losses
        return

    # Get all permissions for the old content type
    old_perms = Permission.objects.using(db_alias).filter(content_type=old_ct)

    # Create equivalent permissions for the new content type
    for old_perm in old_perms:
        new_perm = (
            Permission.objects.using(db_alias)
            .filter(
                content_type=new_ct,
                codename=old_perm.codename,
            )
            .first()
        )
        if not new_perm:
            # This should exist at this point, but if not, let's cut our losses
            continue

        # Global user permissions
        User = apps.get_model("authentik_core", "User")
        User.user_permissions.through.objects.using(db_alias).filter(
            permission=old_perm
        ).all().update(permission=new_perm)

        # Global role permissions
        DjangoGroup = apps.get_model("auth", "Group")
        DjangoGroup.permissions.through.objects.using(db_alias).filter(
            permission=old_perm
        ).all().update(permission=new_perm)

        # Object user permissions
        UserObjectPermission = apps.get_model("guardian", "UserObjectPermission")
        UserObjectPermission.objects.using(db_alias).filter(permission=old_perm).all().update(
            permission=new_perm, content_type=new_ct
        )

        # Object role permissions
        GroupObjectPermission = apps.get_model("guardian", "GroupObjectPermission")
        GroupObjectPermission.objects.using(db_alias).filter(permission=old_perm).all().update(
            permission=new_perm, content_type=new_ct
        )


def remove_old_authenticated_session_content_type(
    apps: Apps, schema_editor: BaseDatabaseSchemaEditor
):
    db_alias = schema_editor.connection.alias
    ContentType = apps.get_model("contenttypes", "ContentType")

    ContentType.objects.using(db_alias).filter(model="oldauthenticatedsession").delete()


class Migration(migrations.Migration):

    dependencies = [
        ("authentik_core", "0047_delete_oldauthenticatedsession"),
    ]

    operations = [
        migrations.RunPython(
            code=migrate_authenticated_session_permissions,
            reverse_code=migrations.RunPython.noop,
        ),
        migrations.RunPython(
            code=remove_old_authenticated_session_content_type,
            reverse_code=migrations.RunPython.noop,
        ),
    ]
