"""Physical units and permanently reserved identifier history."""
import uuid

from django.core.exceptions import ValidationError
from django.db import models

from apps.catalog.models import ProductModel, ProductVariant
from apps.organization.model_base import TimeStampedModel
from .identification import normalize_identifier


class RegistryQuerySet(models.QuerySet):
    def delete(self):
        raise ValidationError("Registry history cannot be deleted through normal workflows.")


class RegistryRecord(TimeStampedModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    is_active = models.BooleanField(default=True)
    objects = RegistryQuerySet.as_manager()

    class Meta:
        abstract = True
        ordering = ["created_at", "id"]

    def delete(self, *args, **kwargs):
        raise ValidationError("Registry history cannot be deleted through normal workflows.")

    def _persist(self, *, update_fields=None):
        """Internal service-only persistence, inside its locks and transaction."""
        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)


class Device(RegistryRecord):
    product_model = models.ForeignKey(ProductModel, on_delete=models.PROTECT, related_name="devices")
    product_variant = models.ForeignKey(ProductVariant, null=True, blank=True,
                                        on_delete=models.PROTECT, related_name="devices")

    def __str__(self):
        return f"{self.product_model.brand.code} {self.product_model.code} · {str(self.pk)[:8]}"

    def clean(self):
        super().clean()
        if self.product_variant_id and not ProductVariant.objects.filter(
            pk=self.product_variant_id, product_model_id=self.product_model_id,
        ).exists():
            raise ValidationError("Variant must belong to the selected ProductModel.")
        previous = type(self).objects.filter(pk=self.pk).first()
        if previous and (previous.product_model_id != self.product_model_id
                         or previous.product_variant_id != self.product_variant_id):
            raise ValidationError("Device ProductModel and ProductVariant are immutable.")

    def save(self, *args, **kwargs):
        # Device has no ordinary editable metadata in this phase. A no-op admin
        # edit must not save a stale active flag or bypass registration policy.
        raise ValidationError("Use device registration or lifecycle services.")


class DeviceIdentifier(RegistryRecord):
    class Type(models.TextChoices):
        IMEI1 = "IMEI1", "IMEI 1"
        IMEI2 = "IMEI2", "IMEI 2"
        SERIAL = "SERIAL", "Serial"

    device = models.ForeignKey(Device, on_delete=models.PROTECT, related_name="identifiers")
    identifier_type = models.CharField(max_length=6, choices=Type.choices)
    value = models.CharField(max_length=128)
    normalized_value = models.CharField(max_length=128, editable=False)
    identity_key = models.CharField(max_length=128, editable=False)

    class Meta(RegistryRecord.Meta):
        constraints = [
            models.CheckConstraint(condition=models.Q(identifier_type__in=["IMEI1", "IMEI2", "SERIAL"]), name="devices_identifier_type_valid"),
            models.CheckConstraint(condition=~models.Q(value="") & ~models.Q(normalized_value="") & ~models.Q(identity_key=""), name="devices_identifier_nonblank"),
            models.CheckConstraint(condition=models.Q(identifier_type="SERIAL") | (
                models.Q(normalized_value__regex=r"^[0-9]{15}$") & models.Q(identity_key=models.F("normalized_value"))
            ), name="devices_imei_canonical"),
            models.UniqueConstraint(fields=["device", "identifier_type"], condition=models.Q(is_active=True), name="devices_active_slot_uniq"),
            # No is_active condition: corrections/deactivation never free identity.
            models.UniqueConstraint(fields=["normalized_value"], condition=models.Q(identifier_type__in=["IMEI1", "IMEI2"]), name="devices_imei_reserved_uniq"),
            models.UniqueConstraint(fields=["normalized_value"], condition=models.Q(identifier_type="SERIAL"), name="devices_serial_reserved_uniq"),
            models.UniqueConstraint(fields=["identity_key"], name="devices_identity_key_reserved_uniq"),
        ]

    def __str__(self):
        return f"{self.identifier_type} record {self.pk}"

    def clean_fields(self, exclude=None):
        self.value, self.normalized_value, self.identity_key = normalize_identifier(self.identifier_type, self.value)
        super().clean_fields(exclude=exclude)

    def clean(self):
        super().clean()
        previous = type(self).objects.filter(pk=self.pk).first()
        if previous and any(getattr(previous, field) != getattr(self, field) for field in (
            "device_id", "identifier_type", "value", "normalized_value", "identity_key",
        )):
            raise ValidationError("Identifier ownership, type and values are immutable; use correction services.")

    def save(self, *args, **kwargs):
        raise ValidationError("Use the identifier correction service; direct writes would bypass history.")


from .evidence import DevicePurchaseEvidence, DeviceWarrantyCoverage  # noqa: E402
from .relationships import CustomerDeviceRelationship  # noqa: E402
