from contextlib import suppress
from typing import Any, Callable, ClassVar, Type

from constance.admin import Config
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
from django.apps import AppConfig, apps
from django.conf import settings
from django.contrib.admin import register, site
from django.contrib.gis.admin import GISModelAdmin
from django.contrib.messages import constants as messages
from django.db.models import Model
from django.db.models.query import QuerySet
from django.http import HttpRequest
from django.utils.translation import gettext_lazy as _
from django_celery_beat.admin import ClockedScheduleAdmin as BaseClockedScheduleAdmin
from django_celery_beat.admin import CrontabScheduleAdmin as BaseCrontabScheduleAdmin
from django_celery_beat.admin import PeriodicTaskAdmin as BasePeriodicTaskAdmin
from django_celery_beat.admin import PeriodicTaskForm, TaskSelectWidget
from django_celery_beat.models import (
    ClockedSchedule,
    CrontabSchedule,
    IntervalSchedule,
    PeriodicTask,
    SolarSchedule,
)
from djangoql.admin import DjangoQLSearchMixin
from import_export.admin import ImportExportModelAdmin
from modeltranslation.translator import NotRegistered, translator
from modeltranslation.utils import get_translation_fields
from mptt.admin import DraggableMPTTAdmin
from unfold.admin import ModelAdmin, TabularInline
from unfold.contrib.import_export.forms import ExportForm, ImportForm
from unfold.decorators import action
from unfold.typing import FieldsetsType
from unfold.widgets import UnfoldAdminSelectWidget, UnfoldAdminTextInputWidget

from engine.core.forms import (
    CRMForm,
    OrderForm,
    OrderProductForm,
    StockForm,
    VendorForm,
)
from engine.core.models import (
    Address,
    Attribute,
    AttributeGroup,
    AttributeValue,
    Brand,
    Category,
    CategoryTag,
    CustomerRelationshipManagementProvider,
    Feedback,
    Order,
    OrderCrmLink,
    OrderProduct,
    Product,
    ProductImage,
    ProductTag,
    PromoCode,
    Promotion,
    Stock,
    Vendor,
    Wishlist,
)


class FieldsetsMixin:
    general_fields: list[str] | None = []
    relation_fields: list[str] | None = []
    additional_fields: list[str] | None = []
    model: ClassVar[Type[Model]]

    def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> FieldsetsType:
        if request:
            pass

        if obj:
            pass

        fieldsets = []

        def add_translations_fieldset(
            fss: FieldsetsType,
        ) -> FieldsetsType:
            with suppress(NotRegistered):
                transoptions = translator.get_options_for_model(self.model)
                translation_fields = []
                for orig in transoptions.local_fields:
                    translation_fields += get_translation_fields(orig)
                if translation_fields:
                    fss = list(fss) + [
                        (
                            _("translations"),
                            {"classes": ["tab"], "fields": translation_fields},
                        )
                    ]
            return fss

        if self.general_fields:
            fieldsets.append(
                (_("general"), {"classes": ["tab"], "fields": self.general_fields})
            )
        if self.relation_fields:
            fieldsets.append(
                (_("relations"), {"classes": ["tab"], "fields": self.relation_fields})
            )
        if self.additional_fields:
            fieldsets.append(
                (
                    _("additional info"),
                    {"classes": ["tab"], "fields": self.additional_fields},
                )
            )
        opts = self.model._meta

        meta_fields = []

        if any(f.name == "uuid" for f in opts.fields):
            meta_fields.append("uuid")

        if any(f.name == "slug" for f in opts.fields):
            meta_fields.append("slug")

        if any(f.name == "sku" for f in opts.fields):
            meta_fields.append("sku")

        if any(f.name == "human_readable_id" for f in opts.fields):
            meta_fields.append("human_readable_id")

        if meta_fields:
            fieldsets.append(
                (_("metadata"), {"classes": ["tab"], "fields": meta_fields})
            )

        ts = []
        for name in ("created", "modified"):
            if any(f.name == name for f in opts.fields):
                ts.append(name)
        if ts:
            fieldsets.append((_("timestamps"), {"classes": ["tab"], "fields": ts}))
        fieldsets = add_translations_fieldset(fieldsets)
        return fieldsets


# noinspection PyUnresolvedReferences
class ActivationActionsMixin:
    message_user: Callable
    actions_on_top = True
    actions_on_bottom = True
    actions = [
        "delete_selected",
        "activate_selected",
        "deactivate_selected",
    ]

    @action(
        description=_("activate selected %(verbose_name_plural)s").lower(),
        permissions=["change"],
    )
    def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None:
        try:
            queryset.update(is_active=True)
            self.message_user(
                request=request,
                message=_("selected items have been activated.").lower(),
                level=messages.SUCCESS,
            )

        except Exception as e:
            self.message_user(request=request, message=str(e), level=messages.ERROR)

    @action(
        description=_("deactivate selected %(verbose_name_plural)s").lower(),
        permissions=["change"],
    )
    def deactivate_selected(
        self, request: HttpRequest, queryset: QuerySet[Any]
    ) -> None:
        try:
            queryset.update(is_active=False)
            self.message_user(
                request=request,
                message=_("selected items have been deactivated.").lower(),
                level=messages.SUCCESS,
            )

        except Exception as e:
            self.message_user(request=request, message=str(e), level=messages.ERROR)


class AttributeValueInline(TabularInline):
    model = AttributeValue
    extra = 0
    autocomplete_fields = ["attribute"]
    verbose_name = _("attribute value")
    verbose_name_plural = _("attribute values")
    tab = True

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("attribute", "product")


class ProductImageInline(TabularInline):
    model = ProductImage
    extra = 0
    tab = True
    verbose_name = _("image")
    verbose_name_plural = _("images")

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("product")


class StockInline(TabularInline):
    model = Stock
    extra = 0
    form = StockForm
    tab = True
    verbose_name = _("stock")
    verbose_name_plural = _("stocks")

    def get_queryset(self, request):
        return super().get_queryset(request).select_related("vendor", "product")


class OrderProductInline(TabularInline):
    model = OrderProduct
    extra = 0
    readonly_fields = ("product", "quantity", "buy_price")
    form = OrderProductForm
    verbose_name = _("order product")
    verbose_name_plural = _("order products")
    tab = True

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("product")
            .only("product__name")
        )


class CategoryChildrenInline(TabularInline):
    model = Category
    fk_name = "parent"
    extra = 0
    fields = ("name", "description", "is_active", "image", "markup_percent")
    tab = True
    verbose_name = _("children")
    verbose_name_plural = _("children")


@register(AttributeGroup)
class AttributeGroupAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = AttributeGroup
    list_display = (
        "name",
        "modified",
    )
    search_fields = (
        "uuid",
        "name",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "name",
        "parent",
    ]


@register(Attribute)
class AttributeAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Attribute
    list_display = (
        "name",
        "group",
        "value_type",
        "modified",
    )
    list_filter = (
        "value_type",
        "group",
        "is_active",
    )
    search_fields = (
        "uuid",
        "name",
        "group__name",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = [
        "group",
    ]
    general_fields = [
        "is_active",
        "name",
        "value_type",
        "is_filterable",
    ]
    relation_fields = [
        "group",
    ]


@register(AttributeValue)
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
    # noinspection PyClassVar
    model = AttributeValue
    list_display = (
        "attribute",
        "value",
        "modified",
    )
    list_filter = (
        "attribute__group",
        "is_active",
    )
    search_fields = (
        "uuid",
        "value",
        "attribute__name",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = [
        "attribute",
    ]
    general_fields = [
        "is_active",
        "value",
    ]
    relation_fields = [
        "attribute",
        "product",
    ]


@register(Category)
class CategoryAdmin(
    DjangoQLSearchMixin,
    FieldsetsMixin,
    ActivationActionsMixin,
    DraggableMPTTAdmin,
    ModelAdmin,
):
    # noinspection PyClassVar
    model = Category
    list_display = (
        "indented_title",
        "parent",
        "is_active",
        "modified",
    )
    # noinspection PyUnresolvedReferences
    list_filter = (
        "is_active",
        "level",
        "created",
        "modified",
    )
    search_fields = (
        "uuid",
        "name",
    )
    inlines = [
        CategoryChildrenInline,
    ]
    autocomplete_fields = [
        "parent",
        "tags",
    ]
    readonly_fields = (
        "slug",
        "uuid",
        "modified",
        "created",
    )

    general_fields = [
        "is_active",
        "name",
        "description",
        "image",
        "markup_percent",
        "priority",
    ]
    relation_fields = [
        "parent",
        "tags",
    ]


@register(Brand)
class BrandAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Brand
    list_display = (
        "name",
        "priority",
        "is_active",
    )
    list_filter = (
        "categories",
        "is_active",
    )
    search_fields = (
        "uuid",
        "name",
    )
    readonly_fields = (
        "uuid",
        "slug",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "name",
        "description",
        "priority",
    ]
    additional_fields = ["small_logo", "big_logo"]


@register(Product)
class ProductAdmin(
    DjangoQLSearchMixin,
    FieldsetsMixin,
    ActivationActionsMixin,
    ModelAdmin,
    ImportExportModelAdmin,
):
    # noinspection PyClassVar
    model = Product
    list_display = (
        "sku",
        "name",
        "is_active",
        "category",
        "brand",
        "price",
        "rating",
        "modified",
    )
    list_filter = (
        "is_active",
        "is_digital",
        "is_updatable",
        "stocks__vendor",
        "tags__name",
        "created",
        "modified",
    )
    search_fields = (
        "name",
        "partnumber",
        "brand__name",
        "brand__slug",
        "category__name",
        "category__slug",
        "uuid",
        "slug",
        "sku",
    )
    readonly_fields = (
        "sku",
        "slug",
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = (
        "category",
        "brand",
        "tags",
    )
    inlines = [
        AttributeValueInline,
        ProductImageInline,
        StockInline,
    ]
    import_form_class = ImportForm
    export_form_class = ExportForm

    general_fields = [
        "is_active",
        "name",
        "partnumber",
        "is_digital",
    ]
    relation_fields = [
        "category",
        "brand",
        "tags",
    ]
    additional_fields = [
        "is_updatable",
    ]

    def get_queryset(self, request):
        return (
            super()
            .get_queryset(request)
            .select_related("category", "brand")
            .prefetch_related(
                "tags",
                "images",
                "stocks__vendor",
                "attributes__attribute",
            )
        )


@register(ProductTag)
class ProductTagAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = ProductTag
    list_display = ("tag_name",)
    search_fields = ("tag_name",)
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "tag_name",
        "name",
    ]


@register(CategoryTag)
class CategoryTagAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = CategoryTag
    list_display = (
        "name",
        "tag_name",
        "is_active",
    )
    search_fields = (
        "name",
        "tag_name",
        "is_active",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "tag_name",
        "name",
    ]


@register(Vendor)
class VendorAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Vendor
    list_display = (
        "name",
        "markup_percent",
        "modified",
    )
    list_filter = (
        "markup_percent",
        "is_active",
    )
    search_fields = (
        "name",
        "uuid",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
        "last_processing_response",
    )
    form = VendorForm
    general_fields = [
        "is_active",
        "name",
        "markup_percent",
        "authentication",
    ]
    relation_fields = [
        "users",
    ]
    additional_fields = [
        "integration_path",
        "last_processing_response",
        "b2b_auth_token",
    ]


@register(Feedback)
class FeedbackAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Feedback
    list_display = (
        "order_product",
        "rating",
        "comment",
        "modified",
    )
    list_filter = (
        "rating",
        "is_active",
    )
    search_fields = (
        "order_product__product__name",
        "comment",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "rating",
        "comment",
    ]
    relation_fields = [
        "order_product",
    ]


@register(Order)
class OrderAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Order
    list_display = (
        "human_readable_id",
        "user",
        "status",
        "total_price",
        "buy_time",
        "modified",
    )
    list_filter = (
        "status",
        "buy_time",
        "modified",
        "created",
    )
    search_fields = (
        "user__email",
        "status",
        "uuid",
        "human_readable_id",
    )
    readonly_fields = (
        "total_price",
        "total_quantity",
        "human_readable_id",
        "uuid",
        "modified",
        "created",
    )
    inlines = [
        OrderProductInline,
    ]
    form = OrderForm
    general_fields = [
        "is_active",
        "user",
        "status",
        "notifications",
        "attributes",
        "buy_time",
    ]
    relation_fields = [
        "promo_code",
        "billing_address",
        "shipping_address",
    ]


@register(OrderProduct)
class OrderProductAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = OrderProduct
    list_display = (
        "order",
        "product",
        "quantity",
        "buy_price",
        "status",
        "modified",
    )
    list_filter = (
        "status",
        "modified",
    )
    search_fields = (
        "order__user__email",
        "product__name",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    form = OrderProductForm
    general_fields = [
        "is_active",
        "quantity",
        "buy_price",
        "status",
    ]
    relation_fields = [
        "order",
        "product",
    ]


@register(PromoCode)
class PromoCodeAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = PromoCode
    list_display = (
        "code",
        "discount_percent",
        "discount_amount",
        "start_time",
        "end_time",
        "used_on",
    )
    list_filter = (
        "discount_percent",
        "discount_amount",
        "start_time",
        "end_time",
    )
    search_fields = (
        "code",
        "uuid",
        "user__email",
    )
    readonly_fields = (
        "used_on",
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = ("user",)
    general_fields = [
        "is_active",
        "code",
        "discount_amount",
        "discount_percent",
        "start_time",
        "end_time",
        "used_on",
    ]
    relation_fields = [
        "user",
    ]


@register(Promotion)
class PromotionAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Promotion
    list_display = (
        "name",
        "discount_percent",
        "modified",
    )
    search_fields = ("name",)
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = ("products",)
    general_fields = [
        "is_active",
        "name",
        "discount_percent",
        "description",
    ]
    relation_fields = [
        "products",
    ]


@register(Stock)
class StockAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Stock
    form = StockForm
    list_display = (
        "product",
        "vendor",
        "sku",
        "quantity",
        "price",
        "modified",
    )
    list_filter = (
        "vendor",
        "quantity",
    )
    search_fields = (
        "product__name",
        "vendor__name",
        "sku",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = (
        "product",
        "vendor",
    )
    general_fields = [
        "is_active",
        "sku",
        "quantity",
        "price",
        "purchase_price",
        "digital_asset",
    ]
    additional_fields = [
        "system_attributes",
    ]
    relation_fields = [
        "product",
        "vendor",
    ]


@register(Wishlist)
class WishlistAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = Wishlist
    list_display = (
        "user",
        "modified",
    )
    search_fields = (
        "user__email",
        "uuid",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    general_fields = [
        "is_active",
        "user",
    ]
    relation_fields = [
        "products",
    ]


@register(ProductImage)
class ProductImageAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = ProductImage
    list_display = (
        "alt",
        "product",
        "priority",
        "modified",
    )
    list_filter = (
        "priority",
        "modified",
        "created",
    )
    search_fields = (
        "alt",
        "product__name",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    autocomplete_fields = ("product",)
    general_fields = [
        "is_active",
        "alt",
        "priority",
        "image",
    ]
    relation_fields = [
        "product",
    ]


@register(Address)
class AddressAdmin(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin):
    # noinspection PyClassVar
    model = Address
    list_display = (
        "street",
        "city",
        "region",
        "country",
        "user",
    )
    list_filter = (
        "country",
        "region",
    )
    search_fields = (
        "street",
        "city",
        "postal_code",
        "user__email",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    gis_widget_kwargs = {
        "attrs": {
            "default_lon": 37.61556,
            "default_lat": 55.75222,
            "default_zoom": 6,
        }
    }
    general_fields = [
        "is_active",
        "address_line",
        "street",
        "district",
        "city",
        "region",
        "postal_code",
        "country",
        "raw_data",
    ]
    relation_fields = [
        "user",
        "api_response",
    ]


@register(CustomerRelationshipManagementProvider)
class CustomerRelationshipManagementProviderAdmin(
    DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin
):
    # noinspection PyClassVar
    model = CustomerRelationshipManagementProvider
    list_display = (
        "name",
        "default",
    )
    search_fields = (
        "name",
        "uuid",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
    )
    form = CRMForm
    general_fields = [
        "is_active",
        "name",
        "default",
        "integration_url",
        "integration_location",
        "attributes",
        "authentication",
    ]


@register(OrderCrmLink)
class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin):
    # noinspection PyClassVar
    model = OrderCrmLink
    list_display = (
        "crm_lead_id",
        "order",
    )
    search_fields = (
        "crm_lead_id",
        "order__human_readable_id",
        "order__uuid",
        "order__user__uuid",
        "order__user__email",
    )
    readonly_fields = (
        "uuid",
        "modified",
        "created",
        "crm_lead_id",
    )
    general_fields = [
        "is_active",
        "crm_lead_id",
    ]
    relation_fields = [
        "order",
        "crm",
    ]


# Constance configuration
class ConstanceConfig:
    class Meta:
        app_label = "core"
        object_name = "Config"
        concrete_model = None
        model_name = module_name = "config"
        verbose_name_plural = _("Config")
        abstract = False
        swapped = False
        is_composite_pk = False

        def get_change_permission(self) -> str:
            return f"change_{self.model_name}"

        @property
        def app_config(self) -> AppConfig:
            return apps.get_app_config(self.app_label)

        @property
        def label(self) -> str:
            return f"{self.app_label}.{self.object_name}"

        @property
        def label_lower(self) -> str:
            return f"{self.app_label}.{self.model_name}"

        def get_ordered_objects(self) -> bool:
            return False

    _meta = Meta()


site.unregister([Config])  # ty:ignore[invalid-argument-type]
site.register([ConstanceConfig], BaseConstanceAdmin)  # ty:ignore[invalid-argument-type]
site.site_title = settings.PROJECT_NAME
site.site_header = "eVibes"
site.index_title = settings.PROJECT_NAME


site.unregister(PeriodicTask)
site.unregister(IntervalSchedule)
site.unregister(CrontabSchedule)
site.unregister(SolarSchedule)
site.unregister(ClockedSchedule)


class UnfoldTaskSelectWidget(UnfoldAdminSelectWidget, TaskSelectWidget):
    pass


class UnfoldPeriodicTaskForm(PeriodicTaskForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["task"].widget = UnfoldAdminTextInputWidget()
        self.fields["regtask"].widget = UnfoldTaskSelectWidget()


@register(PeriodicTask)
class PeriodicTaskAdmin(BasePeriodicTaskAdmin, ModelAdmin):
    form = UnfoldPeriodicTaskForm


@register(IntervalSchedule)
class IntervalScheduleAdmin(ModelAdmin):
    pass


@register(CrontabSchedule)
class CrontabScheduleAdmin(BaseCrontabScheduleAdmin, ModelAdmin):
    pass


@register(SolarSchedule)
class SolarScheduleAdmin(ModelAdmin):
    pass


@register(ClockedSchedule)
class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
    pass
