# Generated manually to store ISTAT fields on guest records.
from __future__ import annotations

from django.db import migrations, models
from django.db.models import Prefetch


def _derive_guest_type_codes(group_type: str | None, count: int) -> list[str]:
    if count <= 0:
        return []

    normalized = (group_type or "").strip().lower()
    if normalized == "family":
        return ["17"] + ["19"] * (count - 1)
    if normalized == "single":
        return ["16"] * count
    return ["18"] + ["20"] * (count - 1)


def backfill_guest_istat_fields(apps, schema_editor):
    Booking = apps.get_model("bookings", "Booking")
    Guest = apps.get_model("guests", "Guest")

    bookings = Booking.objects.prefetch_related(
        Prefetch(
            "guests",
            queryset=Guest.objects.order_by("-is_main_guest", "created_at", "id"),
        )
    ).order_by("id")

    for booking in bookings:
        guests = list(booking.guests.all())
        if not guests:
            continue

        guest_type_codes = _derive_guest_type_codes(
            booking.guest_group_type,
            len(guests),
        )

        for index, guest in enumerate(guests):
            extra = guest.extra_data if isinstance(guest.extra_data, dict) else {}
            cleaned_extra = dict(extra)
            for field in ("guest_type", "tourism_type", "transport_type"):
                cleaned_extra.pop(field, None)

            guest_type = (
                guest.guest_type
                or extra.get("guest_type")
                or (guest_type_codes[index] if index < len(guest_type_codes) else None)
            )
            tourism_type = guest.tourism_type or extra.get("tourism_type") or booking.tourism_type
            transport_type = guest.transport_type or extra.get("transport_type") or booking.transport_type

            updates = {}
            if guest_type and guest.guest_type != guest_type:
                updates["guest_type"] = guest_type
            if tourism_type and guest.tourism_type != tourism_type:
                updates["tourism_type"] = tourism_type
            if transport_type and guest.transport_type != transport_type:
                updates["transport_type"] = transport_type
            if cleaned_extra != extra:
                updates["extra_data"] = cleaned_extra

            if updates:
                Guest.objects.filter(pk=guest.pk).update(**updates)


def noop_reverse(apps, schema_editor):
    pass


class Migration(migrations.Migration):
    dependencies = [
        ("bookings", "0015_booking_istat_fields"),
        ("guests", "0008_guest_city_tax_exemption_notes_and_more"),
    ]

    operations = [
        migrations.AddField(
            model_name="guest",
            name="guest_type",
            field=models.CharField(
                blank=True,
                choices=[
                    ("16", "Single Guest"),
                    ("17", "Head of Family"),
                    ("18", "Group Leader"),
                    ("19", "Family Member"),
                    ("20", "Group Member"),
                ],
                help_text="ISTAT lodging type code for the guest record",
                max_length=2,
                null=True,
            ),
        ),
        migrations.AddField(
            model_name="guest",
            name="tourism_type",
            field=models.CharField(
                blank=True,
                help_text="ISTAT tourism type associated with the guest",
                max_length=64,
                null=True,
            ),
        ),
        migrations.AddField(
            model_name="guest",
            name="transport_type",
            field=models.CharField(
                blank=True,
                help_text="ISTAT transport type associated with the guest",
                max_length=64,
                null=True,
            ),
        ),
        migrations.RunPython(backfill_guest_istat_fields, noop_reverse),
    ]
