"""
Mixins Admin pour les fonctionnalites reutilisables.
"""
from django.contrib import admin, messages
from django.db import transaction
from django.urls import path
from django.http import HttpResponseRedirect
from django.utils.html import format_html


class OrderableAdminMixin:
    """
    Mixin admin pour les modeles avec champ 'order'.

    Ajoute:
    - Une action pour reinitialiser l'ordre des elements selectionnes
    - Un bouton pour reinitialiser l'ordre de tous les elements
    - Detection automatique des doublons et sauts dans l'ordre
    - Alerte visuelle quand des problemes d'ordre sont detectes

    Usage:
        @admin.register(MyModel)
        class MyModelAdmin(OrderableAdminMixin, admin.ModelAdmin):
            list_display = ['name', 'order', ...]
            list_editable = ['order']
    """

    # Template personnalise avec bouton de reinitialisation
    change_list_template = 'admin/orderable_change_list.html'

    # Champ a utiliser pour l'ordre (peut etre surcharge)
    order_field = 'order'

    # Champs pour grouper le reordonnancement (ex: ['page'] pour PageSection)
    order_group_by = None

    def get_actions(self, request):
        """Ajoute l'action de reinitialisation de l'ordre."""
        actions = super().get_actions(request)
        actions['resequence_order'] = (
            self.resequence_order_action,
            'resequence_order',
            'Reinitialiser l\'ordre (1, 2, 3...)'
        )
        return actions

    def resequence_order_action(self, request, queryset):
        """Action admin pour reinitialiser l'ordre des elements selectionnes."""
        count = self._resequence_queryset(queryset)
        self.message_user(
            request,
            f'{count} element(s) reordonne(s) avec succes.',
            messages.SUCCESS
        )
    resequence_order_action.short_description = 'Reinitialiser l\'ordre (1, 2, 3...)'

    def _resequence_queryset(self, queryset):
        """Resequence l'ordre d'un queryset."""
        order_field = self.order_field

        with transaction.atomic():
            items = list(queryset.order_by(order_field))
            for index, item in enumerate(items, start=1):
                if getattr(item, order_field) != index:
                    setattr(item, order_field, index)
                    item.save(update_fields=[order_field])

        return len(items)

    def _resequence_all(self, request, group_value=None):
        """Resequence tous les elements (ou par groupe)."""
        queryset = self.model.objects.all()

        if self.order_group_by and group_value:
            queryset = queryset.filter(**{self.order_group_by: group_value})

        order_field = self.order_field

        with transaction.atomic():
            items = list(queryset.order_by(order_field, 'pk'))
            updated = 0
            for index, item in enumerate(items, start=1):
                if getattr(item, order_field) != index:
                    setattr(item, order_field, index)
                    item.save(update_fields=[order_field])
                    updated += 1

        return len(items), updated

    def get_urls(self):
        """Ajoute l'URL pour reinitialiser l'ordre."""
        urls = super().get_urls()
        custom_urls = [
            path(
                'resequence-order/',
                self.admin_site.admin_view(self.resequence_order_view),
                name=f'{self.model._meta.app_label}_{self.model._meta.model_name}_resequence'
            ),
        ]
        return custom_urls + urls

    def resequence_order_view(self, request):
        """Vue pour reinitialiser l'ordre de tous les elements."""
        total, updated = self._resequence_all(request)

        if updated > 0:
            self.message_user(
                request,
                f'Ordre reinitialise: {updated}/{total} element(s) mis a jour.',
                messages.SUCCESS
            )
        else:
            self.message_user(
                request,
                f'L\'ordre est deja correct ({total} elements).',
                messages.INFO
            )

        # Retour a la liste
        return HttpResponseRedirect('../')

    def changelist_view(self, request, extra_context=None):
        """Ajoute le bouton et les statistiques d'ordre au contexte."""
        extra_context = extra_context or {}

        # Detecter les problemes d'ordre
        order_stats = self._get_order_stats()
        extra_context['order_stats'] = order_stats
        extra_context['show_resequence_button'] = order_stats['has_issues']
        extra_context['resequence_url'] = 'resequence-order/'

        return super().changelist_view(request, extra_context=extra_context)

    def _get_order_stats(self):
        """Analyse l'etat de l'ordre des elements."""
        order_field = self.order_field
        queryset = self.model.objects.all()

        if not queryset.exists():
            return {
                'has_issues': False,
                'duplicates': 0,
                'gaps': 0,
                'total': 0,
            }

        orders = list(queryset.values_list(order_field, flat=True).order_by(order_field))
        total = len(orders)

        # Compter les doublons
        from collections import Counter
        order_counts = Counter(orders)
        duplicates = sum(1 for count in order_counts.values() if count > 1)

        # Compter les sauts
        expected = list(range(1, total + 1))
        gaps = sum(1 for o in orders if o not in expected) if orders != expected else 0

        # Verifier si l'ordre est parfait (1, 2, 3, ...)
        is_perfect = orders == expected

        return {
            'has_issues': not is_perfect,
            'duplicates': duplicates,
            'gaps': gaps,
            'total': total,
            'is_perfect': is_perfect,
        }


class OrderableInlineMixin:
    """
    Mixin pour les inlines avec champ 'order'.

    Ajoute le tri automatique par ordre.
    """
    order_field = 'order'
    ordering = ['order']

    def get_queryset(self, request):
        """Trie par ordre."""
        qs = super().get_queryset(request)
        return qs.order_by(self.order_field)


class IconPickerAdminMixin:
    """
    Mixin admin pour utiliser le widget IconPicker sur les champs d'icônes.

    Détecte automatiquement les ForeignKey vers le modèle Icon et applique
    le widget visuel de sélection d'icônes.

    Usage:
        @admin.register(MyModel)
        class MyModelAdmin(IconPickerAdminMixin, admin.ModelAdmin):
            pass
    """

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Applique le widget IconPicker aux champs ForeignKey vers Icon."""
        from config.widgets import IconPickerWidget
        from config.models import Icon

        # Vérifier si le champ est une FK vers Icon
        if db_field.related_model == Icon:
            kwargs['widget'] = IconPickerWidget()

        return super().formfield_for_foreignkey(db_field, request, **kwargs)


class IconPickerInlineMixin:
    """
    Mixin pour les inlines avec champs d'icônes.

    Usage:
        class MyInline(IconPickerInlineMixin, admin.TabularInline):
            model = MyModel
    """

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """Applique le widget IconPicker aux champs ForeignKey vers Icon."""
        from config.widgets import IconPickerWidget
        from config.models import Icon

        # Vérifier si le champ est une FK vers Icon
        if db_field.related_model == Icon:
            kwargs['widget'] = IconPickerWidget()

        return super().formfield_for_foreignkey(db_field, request, **kwargs)
