# Generated for Django 6.1.1

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


WINDOW_TYPES = ("SUMMER", "WINTER", "SPECIAL")
WINDOW_STATUSES = ("SCHEDULED", "OPEN", "CLOSED", "CANCELLED")
TRANSFER_STATUSES = (
    "PENDING",
    "REQUIRES_APPROVAL",
    "APPROVED",
    "COMPLETED",
    "REJECTED",
    "CANCELLED",
)
ACTIVE_TRANSFER_STATUSES = ("PENDING", "REQUIRES_APPROVAL", "APPROVED")


def validate_existing_data(apps, schema_editor):
    TransferWindow = apps.get_model("transfers", "TransferWindow")
    Transfer = apps.get_model("transfers", "Transfer")

    for window in TransferWindow.objects.all().iterator():
        if window.window_type not in WINDOW_TYPES:
            raise RuntimeError(
                f"TransferWindow {window.pk} has invalid type {window.window_type!r}."
            )
        if window.status not in WINDOW_STATUSES:
            raise RuntimeError(
                f"TransferWindow {window.pk} has invalid status {window.status!r}."
            )

        valid = False
        if window.status == "SCHEDULED":
            valid = not any((window.opened_at, window.closed_at, window.cancelled_at))
        elif window.status == "OPEN":
            valid = (
                window.opened_at is not None
                and window.closed_at is None
                and window.cancelled_at is None
            )
        elif window.status == "CLOSED":
            valid = (
                window.opened_at is not None
                and window.closed_at is not None
                and window.cancelled_at is None
                and window.closed_at >= window.opened_at
            )
        elif window.status == "CANCELLED":
            valid = (
                window.opened_at is None
                and window.closed_at is None
                and window.cancelled_at is not None
            )

        if not valid:
            raise RuntimeError(
                f"TransferWindow {window.pk} has an inconsistent lifecycle state."
            )

    active_seen = set()
    for transfer in Transfer.objects.all().order_by("created_at", "pk").iterator():
        if transfer.status not in TRANSFER_STATUSES:
            raise RuntimeError(
                f"Transfer {transfer.pk} has invalid status {transfer.status!r}."
            )
        if transfer.transfer_fee < 0:
            raise RuntimeError(f"Transfer {transfer.pk} has a negative transfer fee.")
        if (
            transfer.source_club_id is not None
            and transfer.source_club_id == transfer.destination_club_id
        ):
            raise RuntimeError(
                f"Transfer {transfer.pk} has identical source/destination clubs."
            )

        if transfer.status in ACTIVE_TRANSFER_STATUSES:
            if transfer.player_id in active_seen:
                raise RuntimeError(
                    f"Player {transfer.player_id} has multiple active transfers."
                )
            active_seen.add(transfer.player_id)

        valid = False
        if transfer.status in ("PENDING", "REQUIRES_APPROVAL"):
            valid = (
                transfer.approved_at is None
                and transfer.completed_at is None
                and transfer.rejected_at is None
                and transfer.cancelled_at is None
                and transfer.rejection_reason == ""
            )
        elif transfer.status == "APPROVED":
            valid = (
                transfer.approved_at is not None
                and transfer.completed_at is None
                and transfer.rejected_at is None
                and transfer.cancelled_at is None
                and transfer.rejection_reason == ""
            )
        elif transfer.status == "COMPLETED":
            valid = (
                transfer.approved_at is not None
                and transfer.completed_at is not None
                and transfer.rejected_at is None
                and transfer.cancelled_at is None
                and transfer.rejection_reason == ""
                and transfer.completed_at >= transfer.approved_at
            )
        elif transfer.status == "REJECTED":
            valid = (
                transfer.approved_at is None
                and transfer.completed_at is None
                and transfer.rejected_at is not None
                and transfer.cancelled_at is None
            )
        elif transfer.status == "CANCELLED":
            valid = (
                transfer.completed_at is None
                and transfer.rejected_at is None
                and transfer.cancelled_at is not None
                and transfer.rejection_reason == ""
                and (
                    transfer.approved_at is None
                    or transfer.cancelled_at >= transfer.approved_at
                )
            )

        if not valid:
            raise RuntimeError(
                f"Transfer {transfer.pk} has an inconsistent lifecycle state."
            )


def noop_reverse(apps, schema_editor):
    pass


class Migration(migrations.Migration):
    dependencies = [
        ("transfers", "0002_transfer"),
    ]

    operations = [
        migrations.RunPython(validate_existing_data, noop_reverse),
        migrations.AddConstraint(
            model_name="transferwindow",
            constraint=models.CheckConstraint(
                condition=Q(window_type__in=WINDOW_TYPES),
                name="tw_valid_type",
            ),
        ),
        migrations.AddConstraint(
            model_name="transferwindow",
            constraint=models.CheckConstraint(
                condition=Q(status__in=WINDOW_STATUSES),
                name="tw_valid_status",
            ),
        ),
        migrations.AddConstraint(
            model_name="transferwindow",
            constraint=models.CheckConstraint(
                condition=(
                    Q(
                        status="SCHEDULED",
                        opened_at__isnull=True,
                        closed_at__isnull=True,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status="OPEN",
                        opened_at__isnull=False,
                        closed_at__isnull=True,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status="CLOSED",
                        opened_at__isnull=False,
                        closed_at__isnull=False,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status="CANCELLED",
                        opened_at__isnull=True,
                        closed_at__isnull=True,
                        cancelled_at__isnull=False,
                    )
                ),
                name="tw_lifecycle_consistent",
            ),
        ),
        migrations.AddConstraint(
            model_name="transferwindow",
            constraint=models.CheckConstraint(
                condition=(
                    Q(closed_at__isnull=True)
                    | Q(opened_at__isnull=True)
                    | Q(closed_at__gte=F("opened_at"))
                ),
                name="tw_close_after_open",
            ),
        ),
        migrations.AddConstraint(
            model_name="transfer",
            constraint=models.CheckConstraint(
                condition=Q(status__in=TRANSFER_STATUSES),
                name="transfer_valid_status",
            ),
        ),
        migrations.AddConstraint(
            model_name="transfer",
            constraint=models.UniqueConstraint(
                fields=("player",),
                condition=Q(status__in=ACTIVE_TRANSFER_STATUSES),
                name="unique_active_transfer_per_player",
            ),
        ),
        migrations.AddConstraint(
            model_name="transfer",
            constraint=models.CheckConstraint(
                condition=(
                    Q(
                        status="PENDING",
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status="REQUIRES_APPROVAL",
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status="APPROVED",
                        approved_at__isnull=False,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status="COMPLETED",
                        approved_at__isnull=False,
                        completed_at__isnull=False,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status="REJECTED",
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=False,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status="CANCELLED",
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=False,
                        rejection_reason="",
                    )
                ),
                name="transfer_lifecycle_consistent",
            ),
        ),
        migrations.AddConstraint(
            model_name="transfer",
            constraint=models.CheckConstraint(
                condition=(
                    Q(completed_at__isnull=True)
                    | Q(approved_at__isnull=True)
                    | Q(completed_at__gte=F("approved_at"))
                ),
                name="transfer_complete_after_approval",
            ),
        ),
        migrations.AddConstraint(
            model_name="transfer",
            constraint=models.CheckConstraint(
                condition=(
                    Q(cancelled_at__isnull=True)
                    | Q(approved_at__isnull=True)
                    | Q(cancelled_at__gte=F("approved_at"))
                ),
                name="transfer_cancel_after_approval",
            ),
        ),
    ]
