"""
Mixins pour l'administration Django avec support de traduction

Utilisation:
    from apps.traduction.admin_mixins import TranslatableAdminMixin

    @admin.register(MonModele)
    class MonModeleAdmin(TranslatableAdminMixin, admin.ModelAdmin):
        pass
"""

from django import forms
from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.html import format_html
from django.utils.safestring import mark_safe

from .models import Language, Dictionnaire
from .registry import get_translatable_fields, is_translatable

# Types de widgets pour les traductions
FIELD_TYPE_INPUT = 'input'
FIELD_TYPE_TEXTAREA = 'textarea'
FIELD_TYPE_RICHTEXT = 'richtext'


def get_field_widget_type(model, field_name):
    """
    Determine le type de widget a utiliser pour un champ traduisible.

    Args:
        model: La classe du modele Django
        field_name: Le nom du champ

    Returns:
        'input' pour CharField, 'textarea' pour TextField, 'richtext' pour CKEditor5Field
    """
    try:
        field = model._meta.get_field(field_name)

        # Verifier si c'est un CKEditor5Field
        field_class_name = field.__class__.__name__
        if field_class_name == 'CKEditor5Field':
            return FIELD_TYPE_RICHTEXT

        # Verifier si c'est un TextField
        if isinstance(field, models.TextField):
            return FIELD_TYPE_TEXTAREA

        # Par defaut, utiliser input (CharField et autres)
        return FIELD_TYPE_INPUT

    except Exception:
        return FIELD_TYPE_INPUT


class TranslationInlineFormSet(forms.BaseInlineFormSet):
    """FormSet personnalise pour les traductions inline"""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Pre-remplir avec les langues actives
        if self.instance and self.instance.pk:
            self.languages = Language.get_active_languages()


def make_translated_field_method(field_name, short_description=None):
    """
    Factory pour créer une méthode d'affichage de champ traduit.

    Args:
        field_name: Nom du champ à traduire
        short_description: Label à afficher (optionnel)

    Returns:
        Une méthode utilisable dans list_display
    """
    def method(self, obj):
        lang_code = getattr(self, '_request', None)
        if lang_code:
            lang_code = getattr(lang_code, 'current_language_code', None)
        return obj.get_translated(field_name, language_code=lang_code) or getattr(obj, field_name, '')

    method.short_description = short_description or field_name.replace('_', ' ').title()
    method.admin_order_field = field_name
    return method


class TranslatableAdminMixin:
    """
    Mixin pour ajouter la gestion des traductions dans l'admin

    Ajoute automatiquement les champs de traduction pour chaque langue
    active dans un fieldset separe avec onglets.

    Pour activer les traductions dans list_display, définissez:
        translated_fields = ['field1', 'field2']  # Champs à traduire dans la liste

    Ou utilisez directement le suffixe _translated:
        list_display = ['name_translated', 'description_translated']
    """
    change_form_template = 'admin/traduction/change_form_translatable.html'
    translated_fields = None  # Liste des champs à traduire dans list_display

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._setup_translated_methods()

    def _setup_translated_methods(self):
        """Configure les méthodes pour les champs traduits"""
        translatable = get_translatable_fields(self.model)

        for field_name in translatable:
            method_name = f'{field_name}_translated'
            if not hasattr(self, method_name):
                # Récupérer le verbose_name du champ
                try:
                    field = self.model._meta.get_field(field_name)
                    label = field.verbose_name
                except:
                    label = field_name.replace('_', ' ').title()

                method = make_translated_field_method(field_name, label)
                setattr(self, method_name, method.__get__(self, self.__class__))

    def get_queryset(self, request):
        """Stocke la request pour accéder à la langue courante"""
        self._request = request
        return super().get_queryset(request)

    def get_list_display(self, request):
        """Remplace automatiquement les champs traduisibles par leur version traduite"""
        list_display = super().get_list_display(request)

        if not is_translatable(self.model):
            return list_display

        translatable = get_translatable_fields(self.model)
        translated_fields = self.translated_fields or translatable

        # Convertir en liste pour modification
        new_list_display = list(list_display)

        for i, field in enumerate(new_list_display):
            # Si le champ est traduisible et pas déjà une méthode _translated
            if field in translated_fields and not field.endswith('_translated'):
                method_name = f'{field}_translated'
                if hasattr(self, method_name):
                    new_list_display[i] = method_name

        return new_list_display

    def get_translation_fields(self):
        """Retourne les champs traduisibles pour ce modele"""
        return get_translatable_fields(self.model)

    def get_fieldsets(self, request, obj=None):
        """Ajoute un fieldset pour les traductions si necessaire"""
        fieldsets = super().get_fieldsets(request, obj)

        # Ne pas modifier si pas de champs traduisibles
        if not is_translatable(self.model):
            return fieldsets

        return fieldsets

    def get_changeform_initial_data(self, request):
        """Ajoute les donnees initiales pour les traductions"""
        initial = super().get_changeform_initial_data(request)
        return initial

    def get_field_types(self):
        """Retourne un dictionnaire field_name -> widget_type pour les champs traduisibles"""
        field_types = {}
        for field_name in self.get_translation_fields():
            field_types[field_name] = get_field_widget_type(self.model, field_name)
        return field_types

    def change_view(self, request, object_id, form_url='', extra_context=None):
        """Ajoute le contexte pour les traductions"""
        extra_context = extra_context or {}

        if is_translatable(self.model):
            extra_context['is_translatable'] = True
            extra_context['languages'] = Language.get_active_languages()
            extra_context['translatable_fields'] = self.get_translation_fields()
            extra_context['field_types'] = self.get_field_types()
            extra_context['default_language'] = Language.get_default()

            # Recuperer les traductions existantes
            if object_id:
                obj = self.get_object(request, object_id)
                if obj:
                    extra_context['original'] = obj
                    translations = {}
                    for lang in Language.get_active_languages():
                        translations[lang.code] = {}
                        for field in self.get_translation_fields():
                            trans = Dictionnaire.get_translation(obj, field, lang.code)
                            translations[lang.code][field] = trans or ''
                    extra_context['translations'] = translations

        return super().change_view(request, object_id, form_url, extra_context)

    def add_view(self, request, form_url='', extra_context=None):
        """Ajoute le contexte pour les traductions en mode ajout"""
        extra_context = extra_context or {}

        if is_translatable(self.model):
            extra_context['is_translatable'] = True
            extra_context['languages'] = Language.get_active_languages()
            extra_context['translatable_fields'] = self.get_translation_fields()
            extra_context['field_types'] = self.get_field_types()
            extra_context['default_language'] = Language.get_default()
            extra_context['translations'] = {}

        return super().add_view(request, form_url, extra_context)

    def save_model(self, request, obj, form, change):
        """Sauvegarde le modele et ses traductions"""
        super().save_model(request, obj, form, change)

        # Sauvegarder les traductions
        if is_translatable(self.model):
            self._save_translations(request, obj)

    def _save_translations(self, request, obj):
        """Sauvegarde les traductions depuis les donnees POST"""
        translatable_fields = self.get_translation_fields()
        languages = Language.get_active_languages()

        for lang in languages:
            for field in translatable_fields:
                field_name = f'translation_{lang.code}_{field}'
                if field_name in request.POST:
                    translation_text = request.POST.get(field_name, '').strip()
                    if translation_text:
                        Dictionnaire.set_translation(obj, field, lang, translation_text)
                    else:
                        # Supprimer la traduction si vide
                        content_type = ContentType.objects.get_for_model(obj)
                        Dictionnaire.objects.filter(
                            content_type=content_type,
                            object_id=obj.pk,
                            field=field,
                            language=lang
                        ).delete()

    def get_field_label(self, field_name):
        """Retourne le label d'un champ"""
        try:
            field = self.model._meta.get_field(field_name)
            return field.verbose_name
        except Exception:
            return field_name.replace('_', ' ').title()


class TranslationInline(admin.TabularInline):
    """
    Inline pour afficher les traductions directement

    Alternative au mixin si on prefere voir toutes les traductions
    dans un tableau inline.
    """
    model = Dictionnaire
    extra = 0
    fields = ['language', 'field', 'translation']
    readonly_fields = ['field']

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        return qs.select_related('language')

    def has_add_permission(self, request, obj=None):
        return False


def get_translation_admin_class(model_admin_class):
    """
    Decorateur de classe pour ajouter le support de traduction

    Utilisation:
        @get_translation_admin_class
        @admin.register(MonModele)
        class MonModeleAdmin(admin.ModelAdmin):
            pass
    """
    class TranslatedModelAdmin(TranslatableAdminMixin, model_admin_class):
        pass

    return TranslatedModelAdmin
