from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.db.models import Sum, Count, Q
from django.utils import timezone
from django.contrib import messages
from django.utils.translation import ngettext
from django import forms
from .models import Account, Transaction, TransactionCategory
from datetime import datetime, timedelta

# Constantes pour les URLs admin
ADMIN_ACCOUNT_CHANGE_URL = "admin:banking_account_change"
ADMIN_TRANSACTION_CHANGE_URL = "admin:banking_transaction_change"
ADMIN_USER_CHANGE_URL = "admin:authentication_user_change"
ADMIN_TRANSACTION_LIST_URL = "admin:banking_transaction_changelist"


class TransactionInlineForm(forms.ModelForm):
    """Formulaire personnalisé pour les transactions inline"""

    class Meta:
        model = Transaction
        fields = ["to_account", "amount", "description", "category"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Améliorer les widgets
        self.fields["description"].widget = forms.TextInput(
            attrs={
                "placeholder": "Description de la transaction...",
                "style": "width: 100%;",
            }
        )
        self.fields["amount"].widget = forms.NumberInput(
            attrs={"step": "0.01", "min": "0", "style": "width: 120px;"}
        )

        # Filtrer les comptes disponibles (exclure le compte courant)
        if hasattr(self, "instance") and self.instance.from_account_id:
            self.fields["to_account"].queryset = Account.objects.exclude(
                id=self.instance.from_account_id
            ).filter(is_active=True)


class TransactionInline(admin.TabularInline):
    """Inline pour créer de nouvelles transactions depuis un compte"""

    model = Transaction
    form = TransactionInlineForm
    fk_name = "from_account"  # Spécifie que c'est le compte source
    extra = 1
    max_num = 5
    verbose_name = "💸 Nouvelle Transaction"
    verbose_name_plural = "💸 Créer des Transactions"

    fields = ["to_account", "amount", "description", "category"]

    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)

        # Personnaliser le formset pour pré-filtrer les comptes
        if obj:
            formset.form.base_fields["to_account"].queryset = Account.objects.exclude(
                id=obj.id
            ).filter(is_active=True)

        return formset


class TransactionHistoryInline(admin.TabularInline):
    """Inline pour afficher l'historique des transactions d'un compte"""

    model = Transaction
    # Utiliser from_account comme clé principale - les transactions sortantes
    fk_name = "from_account"
    extra = 0
    max_num = 20  # Limiter à 20 transactions sortantes
    can_delete = False
    verbose_name = "📊 Transaction"
    verbose_name_plural = "📊 Historique des Transactions (sortantes seulement)"

    fields = [
        "transaction_direction",
        "other_account",
        "amount_display",
        "description",
        "category_display",
        "transaction_date",
        "view_details",
    ]
    readonly_fields = [
        "transaction_direction",
        "other_account",
        "amount_display",
        "description",
        "category_display",
        "transaction_date",
        "view_details",
    ]

    def get_queryset(self, request):
        """Récupère les transactions sortantes du compte"""
        qs = super().get_queryset(request)
        return qs.order_by("-created_at")

    def get_formset(self, request, obj=None, **kwargs):
        """Limite le nombre de transactions affichées dans le formset"""
        formset = super().get_formset(request, obj, **kwargs)
        formset.max_num = 20
        formset.extra = 0
        return formset

    def transaction_direction(self, obj):
        """Indique le sens de la transaction"""
        account = getattr(self, "parent_obj", None)
        if not account:
            return "N/A"

        if obj.from_account == account:
            return format_html('<span style="color: red;">📤 Sortie</span>')
        else:
            return format_html('<span style="color: green;">📥 Entrée</span>')

    transaction_direction.short_description = "🔄 Sens"

    def other_account(self, obj):
        """Affiche l'autre compte impliqué dans la transaction"""
        account = getattr(self, "parent_obj", None)
        if not account:
            return "N/A"

        other = obj.to_account if obj.from_account == account else obj.from_account
        change_url = reverse(ADMIN_ACCOUNT_CHANGE_URL, args=[other.pk])
        account_name = other.name
        if len(account_name) > 30:
            account_name = account_name[:30] + "..."

        return format_html(
            '<a href="{}" target="_blank">{}</a>', change_url, account_name
        )

    other_account.short_description = "🏦 Autre Compte"

    def amount_display(self, obj):
        """Affiche le montant avec couleur selon le sens"""
        account = getattr(self, "parent_obj", None)
        if not account:
            return f"{obj.amount:.2f} €"

        if obj.from_account == account:
            return format_html(
                '<span style="color: red; font-weight: bold;">-{:.2f} €</span>',
                obj.amount,
            )
        else:
            return format_html(
                '<span style="color: green; font-weight: bold;">+{:.2f} €</span>',
                obj.amount,
            )

    amount_display.short_description = "💰 Montant"

    def category_display(self, obj):
        """Affiche la catégorie avec badge"""
        color_map = {
            "deposit": "#28a745",
            "withdrawal": "#dc3545",
            "transfer": "#007bff",
            "fee": "#ffc107",
            "interest": "#17a2b8",
            "share_payment": "#6f42c1",
        }
        color = color_map.get(obj.category, "#6c757d")
        badge_style = f"background-color: {color}; color: white; padding: 2px 6px; border-radius: 3px; font-size: 10px;"

        return format_html(
            '<span class="badge" style="{}">{}</span>',
            badge_style,
            obj.get_category_display(),
        )

    category_display.short_description = "🏷️ Catégorie"

    def view_details(self, obj):
        """Lien vers les détails de la transaction"""
        change_url = reverse(ADMIN_TRANSACTION_CHANGE_URL, args=[obj.pk])
        button_style = "font-size: 10px; padding: 2px 6px;"
        return format_html(
            '<a href="{}" class="button" target="_blank" style="{}">📋 Détails</a>',
            change_url,
            button_style,
        )

    view_details.short_description = "Actions"

    def has_add_permission(self, request, obj=None):
        """Empêche l'ajout depuis cet inline (lecture seule)"""
        return False

    def has_change_permission(self, request, obj=None):
        """Empêche la modification depuis cet inline (lecture seule)"""
        return False


class TransactionIncomingInline(admin.TabularInline):
    """Inline pour afficher les transactions entrantes d'un compte"""

    model = Transaction
    # Utiliser to_account pour les transactions entrantes
    fk_name = "to_account"
    extra = 0
    max_num = 20  # Limiter à 20 transactions entrantes
    can_delete = False
    verbose_name = "📥 Transaction Entrante"
    verbose_name_plural = "📥 Transactions Entrantes (20 dernières)"

    fields = [
        "transaction_direction",
        "other_account",
        "amount_display",
        "description",
        "category_display",
        "transaction_date",
        "view_details",
    ]
    readonly_fields = [
        "transaction_direction",
        "other_account",
        "amount_display",
        "description",
        "category_display",
        "transaction_date",
        "view_details",
    ]

    def get_queryset(self, request):
        """Récupère les transactions entrantes du compte"""
        qs = super().get_queryset(request)
        return qs.order_by("-created_at")

    def transaction_direction(self, obj):
        """Indique le sens de la transaction"""
        return format_html('<span style="color: green;">📥 Entrée</span>')

    transaction_direction.short_description = "🔄 Sens"

    def other_account(self, obj):
        """Affiche l'autre compte impliqué dans la transaction"""
        other = obj.from_account
        change_url = reverse(ADMIN_ACCOUNT_CHANGE_URL, args=[other.pk])
        account_name = other.name
        if len(account_name) > 30:
            account_name = account_name[:30] + "..."

        return format_html(
            '<a href="{}" target="_blank">{}</a>', change_url, account_name
        )

    other_account.short_description = "🏦 Autre Compte"

    def amount_display(self, obj):
        """Affiche le montant avec couleur selon le sens"""
        return format_html(
            '<span style="color: green; font-weight: bold;">+{:.2f} €</span>',
            obj.amount,
        )

    amount_display.short_description = "💰 Montant"

    def category_display(self, obj):
        """Affiche la catégorie avec badge"""
        color_map = {
            "deposit": "#28a745",
            "withdrawal": "#dc3545",
            "transfer": "#007bff",
            "fee": "#ffc107",
            "interest": "#17a2b8",
            "share_payment": "#6f42c1",
        }
        color = color_map.get(obj.category, "#6c757d")
        badge_style = f"background-color: {color}; color: white; padding: 2px 6px; border-radius: 3px; font-size: 10px;"

        return format_html(
            '<span class="badge" style="{}">{}</span>',
            badge_style,
            obj.get_category_display(),
        )

    category_display.short_description = "🏷️ Catégorie"

    def view_details(self, obj):
        """Lien vers les détails de la transaction"""
        change_url = reverse(ADMIN_TRANSACTION_CHANGE_URL, args=[obj.pk])
        button_style = "font-size: 10px; padding: 2px 6px;"
        return format_html(
            '<a href="{}" class="button" target="_blank" style="{}">📋 Détails</a>',
            change_url,
            button_style,
        )

    view_details.short_description = "Actions"

    def has_add_permission(self, request, obj=None):
        """Empêche l'ajout depuis cet inline (lecture seule)"""
        return False

    def has_change_permission(self, request, obj=None):
        """Empêche la modification depuis cet inline (lecture seule)"""
        return False


@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    """Administration avancée pour les comptes financiers."""

    # Ajouter les inlines
    inlines = [TransactionIncomingInline, TransactionHistoryInline, TransactionInline]

    list_display = (
        "account_info",
        "type_badge",
        "balance_display",
        "owner_info",
        "manager_info",
        "transactions_count",
        "last_transaction",
        "activity_status",
        "created_at",
    )

    list_filter = (
        "type",
        "is_active",
        "created_at",
        ("owner", admin.RelatedOnlyFieldListFilter),
        ("account_manager", admin.RelatedOnlyFieldListFilter),
    )

    search_fields = (
        "name",
        "account_number",
        "iban",
        "owner__email",
        "owner__first_name",
        "owner__last_name",
        "account_manager__email",
    )

    readonly_fields = (
        "id",
        "balance_display",
        "transactions_count",
        "last_transaction",
        "total_incoming",
        "total_outgoing",
        "created_at",
        "updated_at",
        "view_transactions_link",
    )

    fieldsets = (
        (
            "🏦 Informations du compte",
            {
                "fields": (
                    "name",
                    "type",
                    "account_number",
                    "iban",
                    "balance_display",
                ),
                "classes": ("wide",),
            },
        ),
        (
            "👥 Propriétaire et gestion",
            {
                "fields": ("owner", "account_manager"),
                "classes": ("wide",),
            },
        ),
        (
            "📊 Statistiques",
            {
                "fields": (
                    "transactions_count",
                    "total_incoming",
                    "total_outgoing",
                    "last_transaction",
                    "view_transactions_link",
                ),
                "classes": ("collapse",),
            },
        ),
        (
            "🗂️ Métadonnées",
            {
                "fields": (
                    "id",
                    "is_active",
                    "created_at",
                    "updated_at",
                    "created_by",
                    "updated_by",
                ),
                "classes": ("collapse",),
            },
        ),
    )

    actions = ["activate_accounts", "deactivate_accounts", "sync_account_balance"]
    list_per_page = 25

    def account_info(self, obj):
        """Affiche les informations du compte avec icône."""
        return format_html(
            "<div><strong>{}</strong><br><small>📄 {}</small></div>",
            obj.name,
            obj.account_number or "Pas de numéro",
        )

    account_info.short_description = "🏦 Compte"

    def type_badge(self, obj):
        """Affiche le type de compte avec badge coloré."""
        colors = {
            "CURRENT": "blue",
            "SAVINGS": "green",
            "SHARE_CAPITAL": "purple",
            "SOLIDARITY_FUND": "orange",
            "RESERVE_FUND": "dark",
            "CASH_DESK": "success",
            "MOBILE_MONEY": "info",
            "LOAN_FUND": "warning",
            "INTEREST_INCOME": "primary",
            "LOAN_LOSS_RESERVE": "danger",
        }
        color = colors.get(obj.type, "secondary")
        return format_html(
            '<span class="badge badge-{}">{}</span>',
            color,
            obj.get_type_display(),
        )

    type_badge.short_description = "📋 Type"

    def balance_display(self, obj):
        """Affiche le solde avec couleur selon le montant."""
        if obj.balance > 0:
            return format_html(
                '<span style="color: green; font-weight: bold;">💰 {} €</span>',
                f"{obj.balance:.2f}",
            )
        elif obj.balance < 0:
            return format_html(
                '<span style="color: red; font-weight: bold;">⚠️ {} €</span>',
                f"{obj.balance:.2f}",
            )
        else:
            return format_html('<span style="color: gray;">➖ 0.00 €</span>')

    balance_display.short_description = "💰 Solde"

    def owner_info(self, obj):
        """Affiche les informations du propriétaire."""
        if obj.owner:
            url = reverse(ADMIN_USER_CHANGE_URL, args=[obj.owner.pk])
            return format_html(
                '<a href="{}" target="_blank">{}</a>',
                url,
                obj.owner.get_full_name() or obj.owner.email,
            )
        return format_html('<span style="color: gray;">Aucun propriétaire</span>')

    owner_info.short_description = "👤 Propriétaire"

    def manager_info(self, obj):
        """Affiche les informations du gestionnaire."""
        if obj.account_manager:
            url = reverse(ADMIN_USER_CHANGE_URL, args=[obj.account_manager.pk])
            return format_html(
                '<a href="{}" target="_blank">👨‍💼 {}</a>',
                url,
                obj.account_manager.get_full_name() or obj.account_manager.email,
            )
        return format_html('<span style="color: gray;">Aucun gestionnaire</span>')

    manager_info.short_description = "👨‍💼 Gestionnaire"

    def transactions_count(self, obj):
        """Compte le nombre de transactions."""
        incoming = obj.incoming_transactions.count()
        outgoing = obj.outgoing_transactions.count()
        total = incoming + outgoing
        return format_html("📊 {} (↗️ {} | ↙️ {})", total, incoming, outgoing)

    transactions_count.short_description = "📊 Transactions"

    def last_transaction(self, obj):
        """Affiche la dernière transaction."""
        last_in = obj.incoming_transactions.order_by("-created_at").first()
        last_out = obj.outgoing_transactions.order_by("-created_at").first()

        last_transaction = None
        if last_in and last_out:
            last_transaction = max(last_in, last_out, key=lambda x: x.created_at)
        elif last_in:
            last_transaction = last_in
        elif last_out:
            last_transaction = last_out

        if last_transaction:
            return format_html(
                "🕐 {} ({})",
                last_transaction.created_at.strftime("%d/%m/%Y %H:%M"),
                last_transaction.get_category_display(),
            )
        return format_html('<span style="color: gray;">Aucune transaction</span>')

    last_transaction.short_description = "🕐 Dernière transaction"

    def activity_status(self, obj):
        """Affiche le statut d'activité."""
        if obj.is_active:
            return format_html('<span style="color: green;">✅ Actif</span>')
        return format_html('<span style="color: red;">❌ Inactif</span>')

    activity_status.short_description = "🔄 Statut"

    def total_incoming(self, obj):
        """Calcule le total des entrées."""
        total = obj.incoming_transactions.aggregate(total=Sum("amount"))["total"] or 0
        return format_html('<span style="color: green;">↗️ {} €</span>', f"{total:.2f}")

    total_incoming.short_description = "↗️ Total entrées"

    def total_outgoing(self, obj):
        """Calcule le total des sorties."""
        total = obj.outgoing_transactions.aggregate(total=Sum("amount"))["total"] or 0
        return format_html('<span style="color: red;">↙️ {} €</span>', f"{total:.2f}")

    total_outgoing.short_description = "↙️ Total sorties"

    def view_transactions_link(self, obj):
        """Lien vers les transactions du compte."""
        incoming_url = (
            f"{reverse(ADMIN_TRANSACTION_LIST_URL)}?to_account__id__exact={obj.pk}"
        )
        outgoing_url = (
            f"{reverse(ADMIN_TRANSACTION_LIST_URL)}?from_account__id__exact={obj.pk}"
        )
        return format_html(
            '<a href="{}" class="button" target="_blank">📥 Entrées</a> '
            '<a href="{}" class="button" target="_blank">📤 Sorties</a>',
            incoming_url,
            outgoing_url,
        )

    view_transactions_link.short_description = "📊 Voir transactions"

    # Actions personnalisées
    def activate_accounts(self, request, queryset):
        """Active les comptes sélectionnés."""
        updated = queryset.update(is_active=True, updated_by=request.user)
        self.message_user(
            request,
            ngettext(
                "✅ %d compte a été activé.",
                "✅ %d comptes ont été activés.",
                updated,
            )
            % updated,
            messages.SUCCESS,
        )

    activate_accounts.short_description = "✅ Activer les comptes sélectionnés"

    def deactivate_accounts(self, request, queryset):
        """Désactive les comptes sélectionnés."""
        updated = queryset.update(is_active=False, updated_by=request.user)
        self.message_user(
            request,
            ngettext(
                "❌ %d compte a été désactivé.",
                "❌ %d comptes ont été désactivés.",
                updated,
            )
            % updated,
            messages.WARNING,
        )

    deactivate_accounts.short_description = "❌ Désactiver les comptes sélectionnés"

    def sync_account_balance(self, request, queryset):
        """Synchronise les soldes des comptes sélectionnés avec leurs transactions."""
        from .signals import recalculate_account_balance

        updated_count = 0
        errors = []

        for account in queryset:
            try:
                old_balance = account.balance
                new_balance = recalculate_account_balance(account)

                if old_balance != new_balance:
                    updated_count += 1
                    self.message_user(
                        request,
                        f"📊 {account.name}: {old_balance} → {new_balance} FCFA",
                        messages.INFO,
                    )

            except Exception as e:
                errors.append(f"{account.name}: {str(e)}")

        if updated_count > 0:
            self.message_user(
                request,
                ngettext(
                    "✅ %d solde de compte a été synchronisé.",
                    "✅ %d soldes de comptes ont été synchronisés.",
                    updated_count,
                )
                % updated_count,
                messages.SUCCESS,
            )
        else:
            self.message_user(
                request, "ℹ️ Tous les soldes étaient déjà à jour.", messages.INFO
            )

        if errors:
            self.message_user(
                request, f"❌ Erreurs: {'; '.join(errors)}", messages.ERROR
            )

    sync_account_balance.short_description = (
        "🔄 Synchroniser les soldes avec les transactions"
    )

    def get_queryset(self, request):
        """Optimise les requêtes."""
        return (
            super()
            .get_queryset(request)
            .select_related("owner", "account_manager", "created_by", "updated_by")
            .prefetch_related("incoming_transactions", "outgoing_transactions")
        )

    def save_model(self, request, obj, form, change):
        """Définit l'utilisateur qui effectue la modification."""
        if not change:  # Création
            obj.created_by = request.user
        obj.updated_by = request.user
        super().save_model(request, obj, form, change)

    def get_inline_instances(self, request, obj=None):
        """Configure les inlines avec l'objet parent"""
        inline_instances = super().get_inline_instances(request, obj)
        for inline in inline_instances:
            if isinstance(inline, TransactionHistoryInline):
                inline.parent_obj = obj
        return inline_instances


@admin.register(Transaction)
class TransactionAdmin(admin.ModelAdmin):
    """Administration avancée pour les transactions financières."""

    list_display = (
        "transaction_info",
        "accounts_display",
        "amount_display",
        "category_badge",
        "transaction_date",
        "created_by",
    )

    list_filter = (
        "category",
        "transaction_date",
        "created_at",
        ("from_account", admin.RelatedOnlyFieldListFilter),
        ("to_account", admin.RelatedOnlyFieldListFilter),
    )

    search_fields = (
        "description",
        "from_account__name",
        "to_account__name",
        "from_account__account_number",
        "to_account__account_number",
        "created_by__email",
    )

    readonly_fields = (
        "id",
        "transaction_date",
        "created_at",
        "updated_at",
        "view_from_account_link",
        "view_to_account_link",
    )

    fieldsets = (
        (
            "💸 Transaction",
            {
                "fields": (
                    "from_account",
                    "to_account",
                    "amount",
                    "description",
                    "category",
                ),
                "classes": ("wide",),
            },
        ),
        (
            "🔗 Liens rapides",
            {
                "fields": ("view_from_account_link", "view_to_account_link"),
                "classes": ("wide",),
            },
        ),
        (
            "🗂️ Métadonnées",
            {
                "fields": (
                    "id",
                    "transaction_date",
                    "created_at",
                    "updated_at",
                    "created_by",
                    "updated_by",
                ),
                "classes": ("collapse",),
            },
        ),
    )

    date_hierarchy = "transaction_date"
    list_per_page = 50

    def transaction_info(self, obj):
        """Affiche les informations de la transaction."""
        return format_html(
            "<div><strong>{}</strong><br><small>🕐 {}</small></div>",
            obj.description[:50] + ("..." if len(obj.description) > 50 else ""),
            obj.transaction_date.strftime("%d/%m/%Y %H:%M"),
        )

    transaction_info.short_description = "💸 Transaction"

    def accounts_display(self, obj):
        """Affiche les comptes source et destination."""
        return format_html(
            "<div>"
            "<small>De:</small> <strong>{}</strong><br>"
            "<small>Vers:</small> <strong>{}</strong>"
            "</div>",
            obj.from_account.name[:20]
            + ("..." if len(obj.from_account.name) > 20 else ""),
            obj.to_account.name[:20] + ("..." if len(obj.to_account.name) > 20 else ""),
        )

    accounts_display.short_description = "🔄 Comptes"

    def amount_display(self, obj):
        """Affiche le montant avec couleur."""
        return format_html(
            '<span style="color: {}; font-weight: bold;">{} €</span>',
            "green" if obj.amount > 0 else "red",
            f"{obj.amount:.2f}",
        )

    amount_display.short_description = "💰 Montant"
    amount_display.admin_order_field = "amount"

    def category_badge(self, obj):
        """Affiche la catégorie avec badge coloré."""
        colors = {
            "deposit": "success",
            "withdrawal": "danger",
            "transfer": "primary",
            "fee": "warning",
            "interest": "info",
            "penalty": "danger",
            "share_subscription": "purple",
            "share_payment": "success",
            "loan_disbursement": "warning",
            "loan_repayment": "success",
        }
        color = colors.get(obj.category, "secondary")
        return format_html(
            '<span class="badge badge-{}">{}</span>',
            color,
            obj.get_category_display(),
        )

    category_badge.short_description = "🏷️ Catégorie"

    def view_from_account_link(self, obj):
        """Lien vers le compte source."""
        url = reverse(ADMIN_ACCOUNT_CHANGE_URL, args=[obj.from_account.pk])
        return format_html(
            '<a href="{}" class="button" target="_blank">📤 Voir compte source</a>',
            url,
        )

    view_from_account_link.short_description = "Compte source"

    def view_to_account_link(self, obj):
        """Lien vers le compte destination."""
        url = reverse(ADMIN_ACCOUNT_CHANGE_URL, args=[obj.to_account.pk])
        return format_html(
            '<a href="{}" class="button" target="_blank">📥 Voir compte destination</a>',
            url,
        )

    view_to_account_link.short_description = "Compte destination"

    def get_queryset(self, request):
        """Optimise les requêtes."""
        return (
            super()
            .get_queryset(request)
            .select_related("from_account", "to_account", "created_by", "updated_by")
        )

    def save_model(self, request, obj, form, change):
        """Définit l'utilisateur qui effectue la modification."""
        if not change:  # Création
            obj.created_by = request.user
        obj.updated_by = request.user
        super().save_model(request, obj, form, change)
