# Generated by Django 5.0.5 on 2024-04-30 09:22

from django.db import migrations, transaction
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps
from django.db.models import Max, Min


def set_include_realm_default_subscriptions_for_existing_prereg_objects(
    apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
    """Here, we set the value of include_realm_default_subscriptions for
    existing PreregistrationUser objects such that its value will
    match what would have happened prior to this migration. There are 3 cases:

    - User was not invited, and is being created by the API, LDAP
      auth, or some other process that does not generate a
      preregistration user object. This requires no migration.

    - User is using an invitation. In that case, both the new and
      previous code-level logic will use the streams on the invitation
      object. So the migration should use False for these.

    - User was not invited, but has a prereg_user created by the
      account registration flow. In this case, for new objects,
      create_preregistration_user create one with the Django models
      default of include_realm_default_subscription=True.

      If the preregistration object has streams specified, usually
      from being copied from an invitation for the user, the previous
      logic would ignore default streams; as a result, existing
      objects with referred_by=None, multiuse_invite=None,
      streams=None should be migrated to
      include_realm_default_subscription=True.
    """
    PreregistrationUser = apps.get_model("zerver", "PreregistrationUser")

    BATCH_SIZE = 1000
    max_id = PreregistrationUser.objects.filter(include_realm_default_subscriptions=None).aggregate(
        Max("id")
    )["id__max"]

    if max_id is None:
        # Do nothing if there are no PreregistrationUser on the server.
        return

    lower_bound = PreregistrationUser.objects.filter(
        include_realm_default_subscriptions=None
    ).aggregate(Min("id"))["id__min"]
    while lower_bound <= max_id:
        upper_bound = lower_bound + BATCH_SIZE - 1
        print(f"Processing batch {lower_bound} to {upper_bound} for PreregistrationUser")

        with transaction.atomic():
            PreregistrationUser.objects.filter(
                id__range=(lower_bound, upper_bound),
                include_realm_default_subscriptions=None,
                referred_by=None,
                multiuse_invite=None,
                streams=None,
            ).update(include_realm_default_subscriptions=True)
            PreregistrationUser.objects.filter(
                id__range=(lower_bound, upper_bound), include_realm_default_subscriptions=None
            ).update(include_realm_default_subscriptions=False)
        lower_bound += BATCH_SIZE


def set_include_realm_default_subscriptions_for_existing_multiuse_invites(
    apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
    MultiuseInvite = apps.get_model("zerver", "MultiuseInvite")

    BATCH_SIZE = 1000
    max_id = MultiuseInvite.objects.filter(include_realm_default_subscriptions=None).aggregate(
        Max("id")
    )["id__max"]

    if max_id is None:
        # Do nothing if there are no MultiuseInvite on the server.
        return

    lower_bound = MultiuseInvite.objects.filter(include_realm_default_subscriptions=None).aggregate(
        Min("id")
    )["id__min"]
    while lower_bound <= max_id:
        upper_bound = lower_bound + BATCH_SIZE - 1
        print(f"Processing batch {lower_bound} to {upper_bound} for MultiuseInvite")

        MultiuseInvite.objects.filter(
            id__range=(lower_bound, upper_bound), include_realm_default_subscriptions=None
        ).update(include_realm_default_subscriptions=False)

        lower_bound += BATCH_SIZE


class Migration(migrations.Migration):
    atomic = False

    dependencies = [
        ("zerver", "0521_multiuseinvite_include_realm_default_subscriptions_and_more"),
    ]

    operations = [
        migrations.RunPython(
            set_include_realm_default_subscriptions_for_existing_prereg_objects,
            elidable=True,
            reverse_code=migrations.RunPython.noop,
        ),
        migrations.RunPython(
            set_include_realm_default_subscriptions_for_existing_multiuse_invites,
            elidable=True,
            reverse_code=migrations.RunPython.noop,
        ),
    ]
