# -*- coding: utf-8 -*-
"""
Authentication Admin Module

This module contains Django admin configurations for authentication models
including login attempts, password reset tokens, email verification tokens,
and user sessions.

Author: Senior Django Developer
Date: 2024
"""

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.utils.html import format_html
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.db.models import Count, Q
from django.utils import timezone
from datetime import timedelta

from .models import (
    LoginAttempt,
    PasswordResetToken,
    EmailVerificationToken,
    UserSession
)


@admin.register(LoginAttempt)
class LoginAttemptAdmin(admin.ModelAdmin):
    """
    Admin configuration for LoginAttempt model.
    
    Provides comprehensive management interface for monitoring
    and analyzing login attempts for security purposes.
    """
    
    # List display configuration
    list_display = [
        'attempted_email',
        'user_link',
        'is_successful',
        'ip_address',
        'country',
        'city',
        'failure_reason',
        'created_at',
        'user_agent_short'
    ]
    
    # List filter configuration
    list_filter = [
        'is_successful',
        'failure_reason',
        'country',
        'created_at',
        ('user', admin.RelatedOnlyFieldListFilter),
    ]
    
    # Search fields configuration
    search_fields = [
        'attempted_email',
        'ip_address',
        'user__email',
        'user__first_name',
        'user__last_name',
        'country',
        'city'
    ]
    
    # Ordering configuration
    ordering = ['-created_at']
    
    # Date hierarchy for easy navigation
    date_hierarchy = 'created_at'
    
    # Read-only fields (login attempts should not be editable)
    readonly_fields = [
        'user',
        'attempted_email',
        'ip_address',
        'user_agent',
        'is_successful',
        'failure_reason',
        'country',
        'city',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by'
    ]
    
    # Fieldsets for organized display
    fieldsets = (
        (_('Login Information'), {
            'fields': (
                'user',
                'attempted_email',
                'is_successful',
                'failure_reason'
            )
        }),
        (_('Technical Details'), {
            'fields': (
                'ip_address',
                'user_agent'
            )
        }),
        (_('Location Information'), {
            'fields': (
                'country',
                'city'
            ),
            'classes': ('collapse',)
        }),
        (_('Metadata'), {
            'fields': (
                'created_at',
                'updated_at',
                'created_by',
                'updated_by'
            ),
            'classes': ('collapse',)
        })
    )
    
    # Pagination
    list_per_page = 50
    
    # Disable add and change permissions (read-only model)
    def has_add_permission(self, request):
        """Disable add permission for login attempts."""
        return False
    
    def has_change_permission(self, request, obj=None):
        """Disable change permission for login attempts."""
        return False
    
    def user_link(self, obj):
        """
        Display a link to the user if exists.
        
        Args:
            obj: LoginAttempt instance
            
        Returns:
            str: HTML link to user or 'Unknown User'
        """
        if obj.user:
            url = reverse('admin:accounts_user_change', args=[obj.user.pk])
            return format_html('<a href="{}">{}</a>', url, obj.user.email)
        return _('Unknown User')
    user_link.short_description = _('User')
    user_link.admin_order_field = 'user__email'
    
    def user_agent_short(self, obj):
        """
        Display a shortened version of user agent.
        
        Args:
            obj: LoginAttempt instance
            
        Returns:
            str: Shortened user agent string
        """
        if obj.user_agent:
            return obj.user_agent[:50] + '...' if len(obj.user_agent) > 50 else obj.user_agent
        return '-'
    user_agent_short.short_description = _('User Agent')
    
    def get_queryset(self, request):
        """
        Optimize queryset with select_related for better performance.
        
        Args:
            request: HTTP request object
            
        Returns:
            QuerySet: Optimized queryset
        """
        return super().get_queryset(request).select_related('user')
    
    # Custom actions
    actions = ['mark_as_suspicious', 'export_failed_attempts']
    
    def mark_as_suspicious(self, request, queryset):
        """
        Custom action to mark IP addresses as suspicious.
        
        Args:
            request: HTTP request object
            queryset: Selected login attempts
        """
        # This would integrate with a security system
        # For now, we'll just show a message
        ip_addresses = queryset.values_list('ip_address', flat=True).distinct()
        self.message_user(
            request,
            _(f'Marked {len(ip_addresses)} IP addresses as suspicious: {", ".join(ip_addresses)}')
        )
    mark_as_suspicious.short_description = _('Mark IP addresses as suspicious')
    
    def export_failed_attempts(self, request, queryset):
        """
        Custom action to export failed login attempts.
        
        Args:
            request: HTTP request object
            queryset: Selected login attempts
        """
        failed_attempts = queryset.filter(is_successful=False)
        count = failed_attempts.count()
        self.message_user(
            request,
            _(f'Exported {count} failed login attempts')
        )
    export_failed_attempts.short_description = _('Export failed login attempts')


@admin.register(PasswordResetToken)
class PasswordResetTokenAdmin(admin.ModelAdmin):
    """
    Admin configuration for PasswordResetToken model.
    
    Provides management interface for password reset tokens
    with security monitoring capabilities.
    """
    
    # List display configuration
    list_display = [
        'user_link',
        'token_short',
        'is_used',
        'is_expired',
        'requested_ip',
        'used_ip',
        'created_at',
        'expires_at'
    ]
    
    # List filter configuration
    list_filter = [
        'is_used',
        'created_at',
        'expires_at',
        ('user', admin.RelatedOnlyFieldListFilter),
    ]
    
    # Search fields configuration
    search_fields = [
        'user__email',
        'user__first_name',
        'user__last_name',
        'token',
        'requested_ip',
        'used_ip'
    ]
    
    # Ordering configuration
    ordering = ['-created_at']
    
    # Date hierarchy for easy navigation
    date_hierarchy = 'created_at'
    
    # Read-only fields
    readonly_fields = [
        'token',
        'expires_at',
        'is_used',
        'used_at',
        'requested_ip',
        'used_ip',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by'
    ]
    
    # Fieldsets for organized display
    fieldsets = (
        (_('Token Information'), {
            'fields': (
                'user',
                'token',
                'is_used',
                'used_at'
            )
        }),
        (_('Expiration'), {
            'fields': (
                'expires_at',
            )
        }),
        (_('IP Tracking'), {
            'fields': (
                'requested_ip',
                'used_ip'
            )
        }),
        (_('Metadata'), {
            'fields': (
                'created_at',
                'updated_at',
                'created_by',
                'updated_by'
            ),
            'classes': ('collapse',)
        })
    )
    
    # Pagination
    list_per_page = 50
    
    def user_link(self, obj):
        """
        Display a link to the user.
        
        Args:
            obj: PasswordResetToken instance
            
        Returns:
            str: HTML link to user
        """
        url = reverse('admin:accounts_user_change', args=[obj.user.pk])
        return format_html('<a href="{}">{}</a>', url, obj.user.email)
    user_link.short_description = _('User')
    user_link.admin_order_field = 'user__email'
    
    def token_short(self, obj):
        """
        Display a shortened version of the token.
        
        Args:
            obj: PasswordResetToken instance
            
        Returns:
            str: Shortened token string
        """
        return f"{obj.token[:8]}...{obj.token[-8:]}"
    token_short.short_description = _('Token')
    
    def is_expired(self, obj):
        """
        Check if the token is expired.
        
        Args:
            obj: PasswordResetToken instance
            
        Returns:
            bool: True if token is expired
        """
        return timezone.now() > obj.expires_at
    is_expired.boolean = True
    is_expired.short_description = _('Is Expired')
    
    def get_queryset(self, request):
        """
        Optimize queryset with select_related for better performance.
        
        Args:
            request: HTTP request object
            
        Returns:
            QuerySet: Optimized queryset
        """
        return super().get_queryset(request).select_related('user')
    
    # Custom actions
    actions = ['cleanup_expired_tokens', 'invalidate_tokens']
    
    def cleanup_expired_tokens(self, request, queryset):
        """
        Custom action to clean up expired tokens.
        
        Args:
            request: HTTP request object
            queryset: Selected tokens
        """
        expired_count = PasswordResetToken.cleanup_expired()
        self.message_user(
            request,
            _(f'Cleaned up {expired_count} expired tokens')
        )
    cleanup_expired_tokens.short_description = _('Clean up expired tokens')
    
    def invalidate_tokens(self, request, queryset):
        """
        Custom action to invalidate selected tokens.
        
        Args:
            request: HTTP request object
            queryset: Selected tokens
        """
        count = queryset.filter(is_used=False).update(
            is_used=True,
            used_at=timezone.now()
        )
        self.message_user(
            request,
            _(f'Invalidated {count} tokens')
        )
    invalidate_tokens.short_description = _('Invalidate selected tokens')


@admin.register(EmailVerificationToken)
class EmailVerificationTokenAdmin(admin.ModelAdmin):
    """
    Admin configuration for EmailVerificationToken model.
    
    Provides management interface for email verification tokens.
    """
    
    # List display configuration
    list_display = [
        'user_link',
        'email',
        'token_short',
        'is_used',
        'is_expired',
        'verified_ip',
        'created_at',
        'expires_at'
    ]
    
    # List filter configuration
    list_filter = [
        'is_used',
        'created_at',
        'expires_at',
        ('user', admin.RelatedOnlyFieldListFilter),
    ]
    
    # Search fields configuration
    search_fields = [
        'user__email',
        'user__first_name',
        'user__last_name',
        'email',
        'token',
        'verified_ip'
    ]
    
    # Ordering configuration
    ordering = ['-created_at']
    
    # Date hierarchy for easy navigation
    date_hierarchy = 'created_at'
    
    # Read-only fields
    readonly_fields = [
        'token',
        'expires_at',
        'is_used',
        'used_at',
        'verified_ip',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by'
    ]
    
    # Fieldsets for organized display
    fieldsets = (
        (_('Verification Information'), {
            'fields': (
                'user',
                'email',
                'token',
                'is_used',
                'used_at'
            )
        }),
        (_('Expiration'), {
            'fields': (
                'expires_at',
            )
        }),
        (_('IP Tracking'), {
            'fields': (
                'verified_ip',
            )
        }),
        (_('Metadata'), {
            'fields': (
                'created_at',
                'updated_at',
                'created_by',
                'updated_by'
            ),
            'classes': ('collapse',)
        })
    )
    
    # Pagination
    list_per_page = 50
    
    def user_link(self, obj):
        """
        Display a link to the user.
        
        Args:
            obj: EmailVerificationToken instance
            
        Returns:
            str: HTML link to user
        """
        url = reverse('admin:accounts_user_change', args=[obj.user.pk])
        return format_html('<a href="{}">{}</a>', url, obj.user.email)
    user_link.short_description = _('User')
    user_link.admin_order_field = 'user__email'
    
    def token_short(self, obj):
        """
        Display a shortened version of the token.
        
        Args:
            obj: EmailVerificationToken instance
            
        Returns:
            str: Shortened token string
        """
        return f"{obj.token[:8]}...{obj.token[-8:]}"
    token_short.short_description = _('Token')
    
    def is_expired(self, obj):
        """
        Check if the token is expired.
        
        Args:
            obj: EmailVerificationToken instance
            
        Returns:
            bool: True if token is expired
        """
        return timezone.now() > obj.expires_at
    is_expired.boolean = True
    is_expired.short_description = _('Is Expired')
    
    def get_queryset(self, request):
        """
        Optimize queryset with select_related for better performance.
        
        Args:
            request: HTTP request object
            
        Returns:
            QuerySet: Optimized queryset
        """
        return super().get_queryset(request).select_related('user')


@admin.register(UserSession)
class UserSessionAdmin(admin.ModelAdmin):
    """
    Admin configuration for UserSession model.
    
    Provides management interface for user sessions with
    device and location tracking.
    """
    
    # List display configuration
    list_display = [
        'user_link',
        'session_key_short',
        'ip_address',
        'device_type',
        'browser',
        'operating_system',
        'is_active',
        'is_expired',
        'last_activity',
        'country',
        'city'
    ]
    
    # List filter configuration
    list_filter = [
        'is_active',
        'device_type',
        'browser',
        'operating_system',
        'country',
        'last_activity',
        'expires_at',
        ('user', admin.RelatedOnlyFieldListFilter),
    ]
    
    # Search fields configuration
    search_fields = [
        'user__email',
        'user__first_name',
        'user__last_name',
        'session_key',
        'ip_address',
        'device_type',
        'browser',
        'operating_system',
        'country',
        'city'
    ]
    
    # Ordering configuration
    ordering = ['-last_activity']
    
    # Date hierarchy for easy navigation
    date_hierarchy = 'last_activity'
    
    # Read-only fields
    readonly_fields = [
        'session_key',
        'ip_address',
        'user_agent',
        'device_type',
        'browser',
        'operating_system',
        'last_activity',
        'expires_at',
        'country',
        'city',
        'created_at',
        'updated_at',
        'created_by',
        'updated_by'
    ]
    
    # Fieldsets for organized display
    fieldsets = (
        (_('Session Information'), {
            'fields': (
                'user',
                'session_key',
                'is_active',
                'last_activity',
                'expires_at'
            )
        }),
        (_('Device Information'), {
            'fields': (
                'ip_address',
                'device_type',
                'browser',
                'operating_system',
                'user_agent'
            )
        }),
        (_('Location Information'), {
            'fields': (
                'country',
                'city'
            ),
            'classes': ('collapse',)
        }),
        (_('Metadata'), {
            'fields': (
                'created_at',
                'updated_at',
                'created_by',
                'updated_by'
            ),
            'classes': ('collapse',)
        })
    )
    
    # Pagination
    list_per_page = 50
    
    def user_link(self, obj):
        """
        Display a link to the user.
        
        Args:
            obj: UserSession instance
            
        Returns:
            str: HTML link to user
        """
        url = reverse('admin:accounts_user_change', args=[obj.user.pk])
        return format_html('<a href="{}">{}</a>', url, obj.user.email)
    user_link.short_description = _('User')
    user_link.admin_order_field = 'user__email'
    
    def session_key_short(self, obj):
        """
        Display a shortened version of the session key.
        
        Args:
            obj: UserSession instance
            
        Returns:
            str: Shortened session key
        """
        return f"{obj.session_key[:8]}...{obj.session_key[-8:]}"
    session_key_short.short_description = _('Session Key')
    
    def is_expired(self, obj):
        """
        Check if the session is expired.
        
        Args:
            obj: UserSession instance
            
        Returns:
            bool: True if session is expired
        """
        return obj.is_expired()
    is_expired.boolean = True
    is_expired.short_description = _('Is Expired')
    
    def get_queryset(self, request):
        """
        Optimize queryset with select_related for better performance.
        
        Args:
            request: HTTP request object
            
        Returns:
            QuerySet: Optimized queryset
        """
        return super().get_queryset(request).select_related('user')
    
    # Custom actions
    actions = ['invalidate_sessions', 'cleanup_expired_sessions']
    
    def invalidate_sessions(self, request, queryset):
        """
        Custom action to invalidate selected sessions.
        
        Args:
            request: HTTP request object
            queryset: Selected sessions
        """
        count = queryset.filter(is_active=True).update(is_active=False)
        self.message_user(
            request,
            _(f'Invalidated {count} sessions')
        )
    invalidate_sessions.short_description = _('Invalidate selected sessions')
    
    def cleanup_expired_sessions(self, request, queryset):
        """
        Custom action to clean up expired sessions.
        
        Args:
            request: HTTP request object
            queryset: Selected sessions
        """
        expired_count = UserSession.cleanup_expired()
        self.message_user(
            request,
            _(f'Cleaned up {expired_count} expired sessions')
        )
    cleanup_expired_sessions.short_description = _('Clean up expired sessions')
