# Generated for the FTG Season integrity review.

from django.db import migrations, models
from django.db.models import F, Q


VALID_STATUSES = {
    "DRAFT",
    "UPCOMING",
    "ACTIVE",
    "COMPLETED",
    "CANCELLED",
    "ARCHIVED",
}


def audit_existing_seasons(apps, schema_editor):
    Season = apps.get_model("seasons", "Season")

    invalid = []

    for season in Season.objects.all().iterator():
        problems = []

        if season.status not in VALID_STATUSES:
            problems.append(f"invalid status={season.status!r}")

        if not 1900 <= season.year <= 2200:
            problems.append(f"year={season.year} outside 1900..2200")

        if season.start_date >= season.end_date:
            problems.append("start_date must be before end_date")

        if season.status in {"DRAFT", "UPCOMING", "CANCELLED"}:
            if any(
                value is not None
                for value in (
                    season.activated_at,
                    season.completed_at,
                    season.archived_at,
                )
            ):
                problems.append(
                    "pre-active/cancelled season has lifecycle timestamps"
                )

        elif season.status == "ACTIVE":
            if season.activated_at is None:
                problems.append("ACTIVE season has no activated_at")
            if season.completed_at is not None or season.archived_at is not None:
                problems.append("ACTIVE season has terminal timestamps")

        elif season.status == "COMPLETED":
            if season.activated_at is None or season.completed_at is None:
                problems.append(
                    "COMPLETED season requires activated_at and completed_at"
                )
            if season.archived_at is not None:
                problems.append("COMPLETED season already has archived_at")

        elif season.status == "ARCHIVED":
            if (
                season.activated_at is None
                or season.completed_at is None
                or season.archived_at is None
            ):
                problems.append(
                    "ARCHIVED season requires all lifecycle timestamps"
                )

        if (
            season.activated_at is not None
            and season.completed_at is not None
            and season.completed_at < season.activated_at
        ):
            problems.append("completed_at is before activated_at")

        if (
            season.completed_at is not None
            and season.archived_at is not None
            and season.archived_at < season.completed_at
        ):
            problems.append("archived_at is before completed_at")

        if problems:
            invalid.append(
                f"Season(pk={season.pk}, name={season.name!r}): "
                + "; ".join(problems)
            )

    if invalid:
        sample = "\n".join(invalid[:20])
        extra = ""
        if len(invalid) > 20:
            extra = f"\n... and {len(invalid) - 20} more invalid row(s)."

        raise RuntimeError(
            "Cannot strengthen Season constraints because legacy data violates "
            "the lifecycle invariants. Repair the listed rows first:\n"
            f"{sample}{extra}"
        )


class Migration(migrations.Migration):

    dependencies = [
        ("seasons", "0001_initial"),
    ]

    operations = [
        migrations.RunPython(
            audit_existing_seasons,
            migrations.RunPython.noop,
        ),
        migrations.AddConstraint(
            model_name="season",
            constraint=models.CheckConstraint(
                condition=Q(year__gte=1900, year__lte=2200),
                name="season_year_1900_2200",
            ),
        ),
        migrations.AddConstraint(
            model_name="season",
            constraint=models.CheckConstraint(
                condition=Q(
                    status__in=[
                        "DRAFT",
                        "UPCOMING",
                        "ACTIVE",
                        "COMPLETED",
                        "CANCELLED",
                        "ARCHIVED",
                    ]
                ),
                name="season_valid_status",
            ),
        ),
        migrations.AddConstraint(
            model_name="season",
            constraint=models.CheckConstraint(
                condition=(
                    Q(
                        status__in=["DRAFT", "UPCOMING", "CANCELLED"],
                        activated_at__isnull=True,
                        completed_at__isnull=True,
                        archived_at__isnull=True,
                    )
                    | Q(
                        status="ACTIVE",
                        activated_at__isnull=False,
                        completed_at__isnull=True,
                        archived_at__isnull=True,
                    )
                    | Q(
                        status="COMPLETED",
                        activated_at__isnull=False,
                        completed_at__isnull=False,
                        archived_at__isnull=True,
                    )
                    | Q(
                        status="ARCHIVED",
                        activated_at__isnull=False,
                        completed_at__isnull=False,
                        archived_at__isnull=False,
                    )
                ),
                name="season_lifecycle_timestamps",
            ),
        ),
        migrations.AddConstraint(
            model_name="season",
            constraint=models.CheckConstraint(
                condition=(
                    Q(activated_at__isnull=True)
                    | Q(completed_at__isnull=True)
                    | Q(completed_at__gte=F("activated_at"))
                ),
                name="season_completed_after_activation",
            ),
        ),
        migrations.AddConstraint(
            model_name="season",
            constraint=models.CheckConstraint(
                condition=(
                    Q(completed_at__isnull=True)
                    | Q(archived_at__isnull=True)
                    | Q(archived_at__gte=F("completed_at"))
                ),
                name="season_archived_after_completion",
            ),
        ),
    ]
