from django.contrib import admin, messages
from django.core.exceptions import ValidationError

from . import services
from .models import Brand, ProductCategory, ProductModel, ProductVariant, DeviceIdentificationPolicy


class CatalogAdmin(admin.ModelAdmin):
    list_display = ("code", "name", "is_active")
    search_fields = ("code", "name")
    list_filter = ("is_active",)
    ordering = ("code",)
    readonly_fields = ("id", "created_at", "updated_at")
    actions = ("deactivate_selected", "reactivate_selected")

    def save_model(self, request, obj, form, change):
        if change:
            # Persist only editable model fields. A stale form must not overwrite
            # readonly lifecycle/applicability flags changed by another operation.
            editable = {field.name for field in obj._meta.concrete_fields if field.editable}
            obj.save(update_fields=editable.intersection(form.fields))
        else:
            super().save_model(request, obj, form, change)

    def get_readonly_fields(self, request, obj=None):
        fields = self.readonly_fields
        if obj is not None:
            fields = (*fields, "is_active")
            if isinstance(obj, ProductModel):
                fields = (*fields, "brand")
            elif isinstance(obj, ProductVariant):
                fields = (*fields, "product_model")
        return fields

    def _lifecycle(self, request, queryset, active):
        operations = {
            Brand: (services.deactivate_brand, services.reactivate_brand, "brand"),
            ProductCategory: (services.deactivate_category, services.reactivate_category, "category"),
            ProductModel: (services.deactivate_product_model, services.reactivate_product_model, "product_model"),
            ProductVariant: (services.deactivate_variant, services.reactivate_variant, "variant"),
        }
        deactivate, reactivate, argument = operations[self.model]
        completed = 0
        for obj in queryset.order_by("pk"):
            try:
                (reactivate if active else deactivate)(**{argument: obj})
            except ValidationError as error:
                self.message_user(request, f"{obj}: {'; '.join(error.messages)}", level=messages.ERROR)
            else:
                completed += 1
        self.message_user(request, f"Lifecycle operation completed for {completed} record(s).")

    @admin.action(description="Deactivate selected records and descendants", permissions=["change"])
    def deactivate_selected(self, request, queryset):
        self._lifecycle(request, queryset, False)

    @admin.action(description="Reactivate selected records only", permissions=["change"])
    def reactivate_selected(self, request, queryset):
        self._lifecycle(request, queryset, True)


@admin.register(Brand)
class BrandAdmin(CatalogAdmin):
    pass


@admin.register(ProductCategory)
class ProductCategoryAdmin(CatalogAdmin):
    pass


@admin.register(ProductModel)
class ProductModelAdmin(CatalogAdmin):
    list_display = ("code", "name", "brand", "category", "is_active")
    list_filter = ("brand", "category", "is_active")
    search_fields = ("code", "name", "brand__code", "brand__name", "category__name")
    list_select_related = ("brand", "category")
    autocomplete_fields = ("brand", "category")


@admin.register(ProductVariant)
class ProductVariantAdmin(CatalogAdmin):
    list_display = ("code", "name", "product_model", "is_active")
    list_filter = ("product_model__brand", "product_model__category", "is_active")
    search_fields = ("code", "name", "product_model__code", "product_model__name")
    list_select_related = ("product_model",)
    autocomplete_fields = ("product_model",)


@admin.register(DeviceIdentificationPolicy)
class DeviceIdentificationPolicyAdmin(admin.ModelAdmin):
    list_display = ("product_model", "imei1_requirement", "imei2_requirement", "serial_requirement")
    list_select_related = ("product_model",)
    search_fields = ("product_model__code", "product_model__name", "product_model__brand__code")
    list_filter = ("imei1_requirement", "imei2_requirement", "serial_requirement")
    ordering = ("product_model__brand__code", "product_model__code")
    autocomplete_fields = ("product_model",)
    readonly_fields = ("id", "created_at", "updated_at")

    def get_readonly_fields(self, request, obj=None):
        return (*self.readonly_fields, "product_model") if obj else self.readonly_fields
