"""Recorded acquisition facts and coverage periods, never claim decisions."""
import uuid
from datetime import date

from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone

from apps.organization.model_base import TimeStampedModel
from .models import Device, RegistryQuerySet


class EvidenceRecord(TimeStampedModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    objects = RegistryQuerySet.as_manager()

    class Meta:
        abstract = True
        ordering = ["created_at", "id"]

    def clean_fields(self, exclude=None):
        for field in self._meta.concrete_fields:
            if isinstance(field, models.CharField):
                value = getattr(self, field.name)
                if isinstance(value, str):
                    setattr(self, field.name, value.strip())
        super().clean_fields(exclude=exclude)

    def clean(self):
        super().clean()
        previous = type(self).objects.filter(pk=self.pk).first()
        if previous and previous.device_id != self.device_id:
            raise ValidationError("Device ownership cannot change.")

    def save(self, *args, **kwargs):
        raise ValidationError("Use purchase evidence or coverage services.")

    def delete(self, *args, **kwargs):
        raise ValidationError("Evidence and coverage history cannot be deleted through normal workflows.")

    def _persist(self, *, update_fields=None):
        self.full_clean()
        if update_fields is not None:
            update_fields = set(update_fields) | {"updated_at"}
        return super().save(using="default", force_insert=self._state.adding, update_fields=update_fields)

    def __str__(self):
        return f"{self._meta.verbose_name} {self.pk}"


class DevicePurchaseEvidence(EvidenceRecord):
    class Status(models.TextChoices):
        UNVERIFIED = "UNVERIFIED", "Unverified"
        VERIFIED = "VERIFIED", "Verified"
        REJECTED = "REJECTED", "Rejected"

    device = models.OneToOneField(Device, on_delete=models.PROTECT, related_name="purchase_evidence")
    purchase_date = models.DateField(null=True, blank=True)
    seller_name = models.CharField(max_length=200, blank=True)
    seller_reference = models.CharField(max_length=128, blank=True)
    invoice_number = models.CharField(max_length=128, blank=True)
    evidence_status = models.CharField(max_length=10, choices=Status.choices, default=Status.UNVERIFIED)
    verification_note = models.CharField(max_length=2000, blank=True)
    reviewed_at = models.DateTimeField(null=True, blank=True, editable=False)
    reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, editable=False,
                                   on_delete=models.PROTECT, related_name="reviewed_device_purchase_evidence")

    class Meta(EvidenceRecord.Meta):
        verbose_name_plural = "device purchase evidence"
        constraints = [
            models.CheckConstraint(condition=models.Q(evidence_status__in=["UNVERIFIED", "VERIFIED", "REJECTED"]), name="devices_purchase_status_valid"),
            models.CheckConstraint(condition=(
                models.Q(evidence_status="UNVERIFIED", reviewed_by__isnull=True, reviewed_at__isnull=True, verification_note="")
                | models.Q(evidence_status__in=["VERIFIED", "REJECTED"], reviewed_by__isnull=False, reviewed_at__isnull=False)
            ), name="devices_purchase_review_coherent"),
        ]

    def clean(self):
        super().clean()
        if isinstance(self.purchase_date, date) and self.purchase_date > timezone.localdate():
            raise ValidationError({"purchase_date": "Purchase date cannot be in the future."})
        if self.evidence_status == self.Status.UNVERIFIED:
            if self.reviewed_by_id or self.reviewed_at or self.verification_note:
                raise ValidationError("Unverified evidence cannot retain review metadata.")
        elif self.evidence_status in (self.Status.VERIFIED, self.Status.REJECTED):
            if not self.reviewed_by_id or not self.reviewed_at:
                raise ValidationError("A review decision requires a reviewer and timestamp.")


class DeviceWarrantyCoverage(EvidenceRecord):
    class Source(models.TextChoices):
        PURCHASE_EVIDENCE = "PURCHASE_EVIDENCE", "Purchase evidence"
        MANUFACTURER_RECORD = "MANUFACTURER_RECORD", "Manufacturer record"
        MANUAL_OVERRIDE = "MANUAL_OVERRIDE", "Manual override"

    device = models.ForeignKey(Device, on_delete=models.PROTECT, related_name="warranty_coverages")
    coverage_start_date = models.DateField()
    coverage_end_date = models.DateField()
    coverage_source = models.CharField(max_length=19, choices=Source.choices)
    reference = models.CharField(max_length=200, blank=True)
    note = models.CharField(max_length=2000, blank=True)
    is_active = models.BooleanField(default=True)

    class Meta(EvidenceRecord.Meta):
        constraints = [
            models.CheckConstraint(condition=models.Q(coverage_source__in=["PURCHASE_EVIDENCE", "MANUFACTURER_RECORD", "MANUAL_OVERRIDE"]), name="devices_coverage_source_valid"),
            models.CheckConstraint(condition=models.Q(coverage_end_date__gte=models.F("coverage_start_date")), name="devices_coverage_date_order"),
            models.CheckConstraint(condition=~models.Q(coverage_source="MANUAL_OVERRIDE") | ~models.Q(note="") | ~models.Q(reference=""), name="devices_coverage_manual_reason"),
            models.UniqueConstraint(fields=["device"], condition=models.Q(is_active=True), name="devices_coverage_active_uniq"),
        ]

    def clean(self):
        super().clean()
        if (isinstance(self.coverage_start_date, date) and isinstance(self.coverage_end_date, date)
                and self.coverage_end_date < self.coverage_start_date):
            raise ValidationError({"coverage_end_date": "Coverage end must be on or after start."})
        if self.coverage_source == self.Source.MANUAL_OVERRIDE and not (self.reference or self.note):
            raise ValidationError("Manual override requires a meaningful reference or note.")
        previous = type(self).objects.filter(pk=self.pk).first()
        if previous:
            fields = ("coverage_start_date", "coverage_end_date", "coverage_source", "reference", "note")
            if any(getattr(self, field) != getattr(previous, field) for field in fields):
                raise ValidationError("Coverage facts are immutable; replace the active coverage.")
