# Generated by Django 3.2.25 on 2025-04-10 11:37

import datetime
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import leprikon.models.fields


def create_group_contacts(apps, schema_editor):
    RegistrationGroup = apps.get_model("leprikon", "RegistrationGroup")
    GroupContact = apps.get_model("leprikon", "GroupContact")

    group_contacts = {
        (g["user_id"], g["name"], g["first_name"], g["last_name"]): g
        for g in RegistrationGroup.objects.annotate(user_id=models.F("registration__user_id")).values(
            "user_id",
            "target_group_id",
            "name",
            "first_name",
            "last_name",
            "street",
            "city",
            "postal_code",
            "phone",
            "email",
            "school_id",
            "school_other",
            "school_class",
            "answers",
        )
    }

    GroupContact.objects.bulk_create(GroupContact(**group_contact) for group_contact in group_contacts.values())


def set_participants_count(apps, schema_editor):
    Registration = apps.get_model("leprikon", "Registration")

    for reg in Registration.objects.filter(activity__registration_type="P"):
        reg.participants_count = reg.participants.count()
        reg.save()

    for reg in Registration.objects.filter(activity__registration_type="G"):
        reg.participants_count = reg.group_members.count()
        reg.save()


def migrate_days_of_week(apps, schema_editor):
    for model_name in ("ActivityTime", "JournalTime"):
        Model = apps.get_model("leprikon", model_name)
        for day in leprikon.models.fields.DayOfWeek:
            Model.objects.filter(day_of_week=day.isoweekday()).update(
                days_of_week=leprikon.models.fields.DaysOfWeek(day)
            )


def migrate_orderable_registrations(apps, schema_editor):
    OrderableRegistration = apps.get_model("leprikon", "OrderableRegistration")
    CalendarEvent = apps.get_model("leprikon", "CalendarEvent")

    for registration in OrderableRegistration.objects.annotate(
        duration=django.db.models.F("activity__orderable__duration")
    ).iterator():
        start_date: datetime.date = registration.start_date
        start_time: datetime.time = registration.start_time or datetime.time(0, 0)
        duration: datetime.timedelta = registration.duration

        if start_time is None:
            end_date = start_date + duration
            end_time = None
        else:
            end = datetime.datetime.combine(start_date, start_time) + duration
            end_date = end.date()
            end_time = end.time()

        registration.calendar_event = CalendarEvent.objects.create(
            name=registration.activity.name,
            activity=registration.activity,
            start_date=start_date,
            start_time=start_time,
            end_date=end_date,
            end_time=end_time,
            is_canceled=registration.canceled is not None,
        )
        registration.save()


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ("leprikon", "0088_activities"),
    ]

    operations = (
        [
            # Add GroupContact model
            migrations.CreateModel(
                name="GroupContact",
                fields=[
                    ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                    ("name", models.CharField(blank=True, default="", max_length=150, verbose_name="group name")),
                    ("first_name", models.CharField(max_length=30, verbose_name="first name")),
                    ("last_name", models.CharField(max_length=30, verbose_name="last name")),
                    ("street", models.CharField(max_length=150, verbose_name="street")),
                    ("city", models.CharField(max_length=150, verbose_name="city")),
                    ("postal_code", leprikon.models.fields.PostalCodeField(verbose_name="postal code")),
                    ("phone", models.CharField(max_length=30, verbose_name="phone")),
                    ("email", leprikon.models.fields.EmailField(max_length=254, verbose_name="email address")),
                    (
                        "school_other",
                        models.CharField(blank=True, default="", max_length=150, verbose_name="other school"),
                    ),
                    ("school_class", models.CharField(blank=True, default="", max_length=30, verbose_name="class")),
                    (
                        "answers",
                        models.TextField(blank=True, default="{}", editable=False, verbose_name="additional answers"),
                    ),
                    (
                        "school",
                        models.ForeignKey(
                            blank=True,
                            null=True,
                            on_delete=django.db.models.deletion.PROTECT,
                            related_name="+",
                            to="leprikon.school",
                            verbose_name="school",
                        ),
                    ),
                    (
                        "target_group",
                        models.ForeignKey(
                            on_delete=django.db.models.deletion.PROTECT,
                            related_name="+",
                            to="leprikon.targetgroup",
                            verbose_name="target group",
                        ),
                    ),
                    (
                        "user",
                        models.ForeignKey(
                            on_delete=django.db.models.deletion.CASCADE,
                            related_name="leprikon_group_contacts",
                            to=settings.AUTH_USER_MODEL,
                            verbose_name="user",
                        ),
                    ),
                ],
                options={
                    "verbose_name": "Group contact",
                    "verbose_name_plural": "Group contacts",
                },
            ),
            migrations.RunPython(create_group_contacts, reverse_code=migrations.RunPython.noop),
            # Add participants_count to Registration
            migrations.AddField(
                model_name="registration",
                name="participants_count",
                field=models.PositiveIntegerField(default=0, verbose_name="participants count"),
                preserve_default=False,
            ),
            migrations.RunPython(set_participants_count, reverse_code=migrations.RunPython.noop),
            # Migrate JournalTime and ActivityTime models to use DaysOfWeekField
        ]
        + [
            migrations.RenameField(
                model_name=model_name,
                old_name=field,
                new_name=f"{field}_time",
            )
            for model_name in ("journaltime", "activitytime")
            for field in ("start", "end")
        ]
        + [
            migrations.AddField(
                model_name="journaltime",
                name="days_of_week",
                field=leprikon.models.fields.DaysOfWeekField(default=0, verbose_name="days of week"),
                preserve_default=False,
            ),
            migrations.AddField(
                model_name="journaltime",
                name="end_date",
                field=models.DateField(
                    blank=True,
                    help_text="If not set, the time is valid for all dates.",
                    null=True,
                    verbose_name="end date",
                ),
            ),
            migrations.AddField(
                model_name="journaltime",
                name="start_date",
                field=models.DateField(
                    blank=True,
                    help_text="If not set, the time is valid for all dates.",
                    null=True,
                    verbose_name="start date",
                ),
            ),
            migrations.AddField(
                model_name="activitytime",
                name="days_of_week",
                field=leprikon.models.fields.DaysOfWeekField(default=0, verbose_name="days of week"),
                preserve_default=False,
            ),
            migrations.AddField(
                model_name="activitytime",
                name="end_date",
                field=models.DateField(
                    blank=True,
                    help_text="If not set, the time is valid for all dates.",
                    null=True,
                    verbose_name="end date",
                ),
            ),
            migrations.AddField(
                model_name="activitytime",
                name="start_date",
                field=models.DateField(
                    blank=True,
                    help_text="If not set, the time is valid for all dates.",
                    null=True,
                    verbose_name="start date",
                ),
            ),
            migrations.AlterField(
                model_name="journaltime",
                name="end_time",
                field=models.TimeField(
                    blank=True,
                    help_text="If end time is 0:00:00, it means the end of the day (effectively 24:00:00).",
                    null=True,
                    verbose_name="end time",
                ),
            ),
            migrations.AlterField(
                model_name="activitytime",
                name="end_time",
                field=models.TimeField(
                    blank=True,
                    help_text="If end time is 0:00:00, it means the end of the day (effectively 24:00:00).",
                    null=True,
                    verbose_name="end time",
                ),
            ),
            migrations.AlterModelOptions(
                name="journaltime",
                options={
                    "ordering": ("start_date", "days_of_week", "start_time"),
                    "verbose_name": "time",
                    "verbose_name_plural": "times",
                },
            ),
            migrations.AlterModelOptions(
                name="activitytime",
                options={
                    "ordering": ("start_date", "days_of_week", "start_time"),
                    "verbose_name": "time",
                    "verbose_name_plural": "times",
                },
            ),
            migrations.RunPython(migrate_days_of_week),
            # Add Resources
            migrations.CreateModel(
                name="Resource",
                fields=[
                    ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                    ("name", models.CharField(max_length=255, verbose_name="name")),
                    (
                        "leader",
                        models.OneToOneField(
                            blank=True,
                            null=True,
                            on_delete=django.db.models.deletion.CASCADE,
                            related_name="resource",
                            to="leprikon.leader",
                            verbose_name="leader",
                        ),
                    ),
                ],
                options={
                    "verbose_name": "resource",
                    "verbose_name_plural": "resources",
                },
            ),
            migrations.CreateModel(
                name="ResourceAvailability",
                fields=[
                    ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                    ("start_date", models.DateField(blank=True, null=True, verbose_name="start date")),
                    ("end_date", models.DateField(blank=True, null=True, verbose_name="end date")),
                    ("days_of_week", leprikon.models.fields.DaysOfWeekField(verbose_name="days of week")),
                    ("start_time", models.TimeField(default=datetime.time(8, 0), verbose_name="start time")),
                    ("end_time", models.TimeField(default=datetime.time(16, 0), verbose_name="end time")),
                    (
                        "resource",
                        models.ForeignKey(
                            on_delete=django.db.models.deletion.CASCADE,
                            related_name="availabilities",
                            to="leprikon.resource",
                            verbose_name="resource",
                        ),
                    ),
                ],
                options={
                    "verbose_name": "availability",
                    "verbose_name_plural": "availabilities",
                    "ordering": ("start_time",),
                },
            ),
            migrations.CreateModel(
                name="ResourceGroup",
                fields=[
                    ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                    ("name", models.CharField(max_length=255, verbose_name="name")),
                    (
                        "resources",
                        models.ManyToManyField(related_name="groups", to="leprikon.Resource", verbose_name="resources"),
                    ),
                ],
                options={
                    "verbose_name": "resource group",
                    "verbose_name_plural": "resource groups",
                },
            ),
            # Migrate OrderableRegistration to use CalendarEvent
            migrations.CreateModel(
                name="CalendarEvent",
                fields=[
                    ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
                    ("name", models.CharField(max_length=255, verbose_name="name")),
                    ("start_date", models.DateField(verbose_name="start date")),
                    ("start_time", models.TimeField(blank=True, null=True, verbose_name="start time")),
                    ("end_date", models.DateField(verbose_name="end date")),
                    ("end_time", models.TimeField(blank=True, null=True, verbose_name="end time")),
                    (
                        "preparation_time",
                        models.DurationField(
                            default=datetime.timedelta(0),
                            help_text="Time to prepare before the event. (HH:MM:SS)",
                            verbose_name="preparation time",
                        ),
                    ),
                    (
                        "recovery_time",
                        models.DurationField(
                            default=datetime.timedelta(0),
                            help_text="Time to recover after the event. (HH:MM:SS)",
                            verbose_name="recovery time",
                        ),
                    ),
                    ("is_canceled", models.BooleanField(default=False, verbose_name="is canceled")),
                    (
                        "resources",
                        models.ManyToManyField(
                            blank=True, related_name="calendar_events", to="leprikon.Resource", verbose_name="resources"
                        ),
                    ),
                    (
                        "resource_groups",
                        models.ManyToManyField(
                            blank=True,
                            related_name="calendar_events",
                            to="leprikon.ResourceGroup",
                            verbose_name="resource groups",
                        ),
                    ),
                    (
                        "activity",
                        models.ForeignKey(
                            blank=True,
                            null=True,
                            on_delete=django.db.models.deletion.CASCADE,
                            related_name="calendar_events",
                            to="leprikon.activity",
                            verbose_name="activity",
                        ),
                    ),
                ],
                options={
                    "verbose_name": "calendar event",
                    "verbose_name_plural": "calendar events",
                    "ordering": ("start_date", "start_time"),
                },
            ),
            migrations.AddField(
                model_name="registration",
                name="calendar_event",
                field=models.OneToOneField(
                    null=True,
                    on_delete=django.db.models.deletion.PROTECT,
                    related_name="registration",
                    to="leprikon.calendarevent",
                    verbose_name="calendar event",
                ),
            ),
            migrations.AddField(
                model_name="activityvariant",
                name="require_group_members_list",
                field=models.BooleanField(
                    default=True,  # defaults to True for existing activity variants only
                    help_text="Require group members list to be filled in registration form. If not set, only the number of group members is required.",
                    verbose_name="require group members list",
                ),
            ),
            migrations.AlterField(
                model_name="activityvariant",
                name="require_group_members_list",
                field=models.BooleanField(
                    default=False,
                    help_text="Require group members list to be filled in registration form. If not set, only the number of group members is required.",
                    verbose_name="require group members list",
                ),
            ),
            migrations.AddField(
                model_name="activityvariant",
                name="required_resources",
                field=models.ManyToManyField(
                    blank=True,
                    related_name="activity_variants",
                    to="leprikon.Resource",
                    verbose_name="required resources",
                ),
            ),
            migrations.AddField(
                model_name="activityvariant",
                name="required_resource_groups",
                field=models.ManyToManyField(
                    blank=True,
                    related_name="activity_variants",
                    to="leprikon.ResourceGroup",
                    verbose_name="required resource groups",
                ),
            ),
            migrations.RunPython(migrate_orderable_registrations),
            migrations.AddField(
                model_name="orderable",
                name="preparation_time",
                field=models.DurationField(
                    default=datetime.timedelta(0),
                    help_text="Time to prepare before the event. (HH:MM:SS)",
                    verbose_name="preparation time",
                ),
            ),
            migrations.AddField(
                model_name="orderable",
                name="recovery_time",
                field=models.DurationField(
                    default=datetime.timedelta(0),
                    help_text="Time to recover after the event. (HH:MM:SS)",
                    verbose_name="recovery time",
                ),
            ),
            migrations.RemoveField(model_name="journaltime", name="day_of_week"),
            migrations.RemoveField(model_name="orderableregistration", name="start_date"),
            migrations.RemoveField(model_name="orderableregistration", name="start_time"),
            migrations.RemoveField(model_name="activitytime", name="day_of_week"),
        ]
    )
