import uuid
from decimal import Decimal

from django.core.validators import MinValueValidator
from django.db import models
from django.db.models import F, Q

from seasons.models import Season

from .constants import (
    TransferStatus,
    TransferWindowStatus,
    TransferWindowType,
)


class TransferWindow(models.Model):
    id = models.BigAutoField(primary_key=True)

    season = models.ForeignKey(
        Season,
        on_delete=models.PROTECT,
        related_name="transfer_windows",
    )
    name = models.CharField(max_length=100)
    window_type = models.CharField(
        max_length=10,
        choices=TransferWindowType.choices,
    )
    start_at = models.DateTimeField()
    end_at = models.DateTimeField()
    status = models.CharField(
        max_length=12,
        choices=TransferWindowStatus.choices,
        default=TransferWindowStatus.SCHEDULED,
    )

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    opened_at = models.DateTimeField(null=True, blank=True)
    closed_at = models.DateTimeField(null=True, blank=True)
    cancelled_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ["start_at", "id"]
        indexes = [
            models.Index(fields=["season", "status"], name="tw_season_status_idx"),
            models.Index(fields=["start_at", "end_at"], name="tw_dates_idx"),
            models.Index(fields=["window_type"], name="tw_type_idx"),
        ]
        constraints = [
            models.CheckConstraint(
                condition=Q(start_at__lt=F("end_at")),
                name="tw_start_before_end",
            ),
            models.UniqueConstraint(
                fields=["season", "name"],
                name="unique_tw_name_per_season",
            ),
            models.CheckConstraint(
                condition=Q(window_type__in=TransferWindowType.values),
                name="tw_valid_type",
            ),
            models.CheckConstraint(
                condition=Q(status__in=TransferWindowStatus.values),
                name="tw_valid_status",
            ),
            models.CheckConstraint(
                condition=(
                    Q(
                        status=TransferWindowStatus.SCHEDULED,
                        opened_at__isnull=True,
                        closed_at__isnull=True,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status=TransferWindowStatus.OPEN,
                        opened_at__isnull=False,
                        closed_at__isnull=True,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status=TransferWindowStatus.CLOSED,
                        opened_at__isnull=False,
                        closed_at__isnull=False,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status=TransferWindowStatus.CANCELLED,
                        opened_at__isnull=True,
                        closed_at__isnull=True,
                        cancelled_at__isnull=False,
                    )
                ),
                name="tw_lifecycle_consistent",
            ),
            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",
            ),
        ]

    def __str__(self):
        return f"{self.season.name} - {self.name}"

    @property
    def is_scheduled(self):
        return self.status == TransferWindowStatus.SCHEDULED

    @property
    def is_open(self):
        return self.status == TransferWindowStatus.OPEN

    @property
    def is_closed(self):
        return self.status == TransferWindowStatus.CLOSED

    @property
    def is_cancelled(self):
        return self.status == TransferWindowStatus.CANCELLED


class Transfer(models.Model):
    ACTIVE_STATUSES = (
        TransferStatus.PENDING,
        TransferStatus.REQUIRES_APPROVAL,
        TransferStatus.APPROVED,
    )

    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    player = models.ForeignKey(
        "players.Player",
        on_delete=models.PROTECT,
        related_name="transfers",
    )
    source_club = models.ForeignKey(
        "clubs.Club",
        on_delete=models.PROTECT,
        related_name="outgoing_transfers",
        null=True,
        blank=True,
    )
    destination_club = models.ForeignKey(
        "clubs.Club",
        on_delete=models.PROTECT,
        related_name="incoming_transfers",
    )
    window = models.ForeignKey(
        "transfers.TransferWindow",
        on_delete=models.PROTECT,
        related_name="transfers",
    )
    source_contract = models.OneToOneField(
        "contracts.Contract",
        on_delete=models.PROTECT,
        related_name="outgoing_completed_transfer",
        null=True,
        blank=True,
    )
    destination_contract = models.OneToOneField(
        "contracts.Contract",
        on_delete=models.PROTECT,
        related_name="incoming_completed_transfer",
        null=True,
        blank=True,
    )
    status = models.CharField(
        max_length=30,
        choices=TransferStatus.choices,
        default=TransferStatus.PENDING,
    )
    transfer_fee = models.DecimalField(
        max_digits=18,
        decimal_places=2,
        default=Decimal("0"),
        validators=[MinValueValidator(Decimal("0"))],
    )
    contract_terms = models.JSONField(null=True, blank=True)
    is_international = models.BooleanField(default=False)

    requested_at = models.DateTimeField(auto_now_add=True)
    approved_at = models.DateTimeField(null=True, blank=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    rejected_at = models.DateTimeField(null=True, blank=True)
    cancelled_at = models.DateTimeField(null=True, blank=True)
    rejection_reason = models.CharField(max_length=255, blank=True, default="")

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["player", "status"]),
            models.Index(fields=["source_club", "status"]),
            models.Index(fields=["destination_club", "status"]),
            models.Index(fields=["window", "status"]),
            models.Index(fields=["status", "created_at"]),
        ]
        constraints = [
            models.CheckConstraint(
                condition=Q(transfer_fee__gte=0),
                name="transfer_fee_nonnegative",
            ),
            models.CheckConstraint(
                condition=(
                    Q(source_club__isnull=True)
                    | ~Q(source_club=F("destination_club"))
                ),
                name="transfer_source_destination_different",
            ),
            models.CheckConstraint(
                condition=Q(status__in=TransferStatus.values),
                name="transfer_valid_status",
            ),
            models.CheckConstraint(
                condition=(
                    Q(source_club__isnull=False)
                    | Q(transfer_fee=Decimal("0"))
                ),
                name="transfer_free_agent_fee_zero",
            ),
            models.CheckConstraint(
                condition=(
                    Q(
                        status=TransferStatus.COMPLETED,
                        destination_contract__isnull=False,
                    )
                    | (
                        ~Q(status=TransferStatus.COMPLETED)
                        & Q(source_contract__isnull=True)
                        & Q(destination_contract__isnull=True)
                    )
                ),
                name="transfer_contract_links_lifecycle",
            ),
            models.CheckConstraint(
                condition=(
                    ~Q(status=TransferStatus.COMPLETED)
                    | Q(source_club__isnull=True, source_contract__isnull=True)
                    | Q(source_club__isnull=False, source_contract__isnull=False)
                ),
                name="transfer_source_contract_consistent",
            ),
            models.UniqueConstraint(
                fields=["player"],
                condition=Q(
                    status__in=[
                        TransferStatus.PENDING,
                        TransferStatus.REQUIRES_APPROVAL,
                        TransferStatus.APPROVED,
                    ]
                ),
                name="unique_active_transfer_per_player",
            ),
            models.CheckConstraint(
                condition=(
                    Q(
                        status=TransferStatus.PENDING,
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status=TransferStatus.REQUIRES_APPROVAL,
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status=TransferStatus.APPROVED,
                        approved_at__isnull=False,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status=TransferStatus.COMPLETED,
                        approved_at__isnull=False,
                        completed_at__isnull=False,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=True,
                        rejection_reason="",
                    )
                    | Q(
                        status=TransferStatus.REJECTED,
                        approved_at__isnull=True,
                        completed_at__isnull=True,
                        rejected_at__isnull=False,
                        cancelled_at__isnull=True,
                    )
                    | Q(
                        status=TransferStatus.CANCELLED,
                        completed_at__isnull=True,
                        rejected_at__isnull=True,
                        cancelled_at__isnull=False,
                        rejection_reason="",
                    )
                ),
                name="transfer_lifecycle_consistent",
            ),
            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",
            ),
            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",
            ),
        ]

    def __str__(self):
        return f"{self.player_id} -> {self.destination_club_id} ({self.status})"

    @property
    def is_active(self):
        return self.status in self.ACTIVE_STATUSES

class TransferApprovalRole(models.TextChoices):
    PLAYER = "PLAYER", "Player"
    SOURCE_CLUB = "SOURCE_CLUB", "Source club"
    DESTINATION_CLUB = "DESTINATION_CLUB", "Destination club"


class TransferPartyApproval(models.Model):
    """Append-only party consent evidence for a permanent transfer."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    transfer = models.ForeignKey(Transfer, on_delete=models.PROTECT, related_name="party_approvals")
    role = models.CharField(max_length=20, choices=TransferApprovalRole.choices)
    approved_by = models.ForeignKey("users.User", on_delete=models.PROTECT, related_name="transfer_party_approvals")
    approved_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["approved_at", "id"]
        constraints = [
            models.UniqueConstraint(fields=["transfer", "role"], name="uq_transfer_party_approval_role"),
            models.CheckConstraint(condition=Q(role__in=TransferApprovalRole.values), name="transfer_party_approval_valid_role"),
        ]
