# -*- coding: utf-8 -*-
"""
Accounts Tasks Module

This module contains Celery tasks for the accounts app, providing
asynchronous operations for user management, email notifications,
data processing, and maintenance tasks.

Tasks:
    - send_welcome_email: Send welcome email to new users
    - send_password_reset_email: Send password reset emails
    - send_account_verification_email: Send email verification
    - cleanup_inactive_users: Remove inactive user accounts
    - generate_user_reports: Generate user analytics reports
    - bulk_user_operations: Perform bulk operations on users
    - sync_user_permissions: Synchronize user permissions
    - backup_user_data: Backup user data

Features:
    - Asynchronous email sending
    - Bulk operations processing
    - Data cleanup and maintenance
    - Report generation
    - Error handling and retries
    - Progress tracking
    - Logging and monitoring

Usage:
    from apps.accounts.tasks import send_welcome_email, cleanup_inactive_users
    
    # Send welcome email asynchronously
    send_welcome_email.delay(user_id)
    
    # Schedule cleanup task
    cleanup_inactive_users.apply_async(countdown=3600)

Configuration:
    - Task routing and queues
    - Retry policies
    - Rate limiting
    - Monitoring and alerts
"""

import logging
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any

from celery import shared_task
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.contrib.sites.models import Site
from django.urls import reverse
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist

from .models import User
from apps.core.utils import send_email_notification

logger = logging.getLogger(__name__)


@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_welcome_email(self, user_id: int) -> Dict[str, Any]:
    """
    Send welcome email to new user.
    
    Args:
        user_id: ID of the user to send email to
    
    Returns:
        Dict: Task result with status and message
    """
    try:
        user = User.objects.get(id=user_id)
        
        # Prepare email context
        context = {
            'user': user,
            'site': Site.objects.get_current(),
            'login_url': reverse('authentification:login'),
            'dashboard_url': reverse('core:dashboard') if 'core:dashboard' in settings.ROOT_URLCONF else '#',
            'support_email': getattr(settings, 'SUPPORT_EMAIL', settings.DEFAULT_FROM_EMAIL)
        }
        
        # Send email
        success = send_email_notification(
            template_name='accounts/emails/welcome',
            context=context,
            to_email=user.email,
            subject=_('Welcome to Ad-tlas Platform')
        )
        
        if success:
            # Update user email sent flag
            user.welcome_email_sent = True
            user.welcome_email_sent_at = timezone.now()
            user.save(update_fields=['welcome_email_sent', 'welcome_email_sent_at'])
            
            logger.info(f'Welcome email sent successfully to {user.email}')
            return {
                'status': 'success',
                'message': f'Welcome email sent to {user.email}',
                'user_id': user_id
            }
        else:
            raise Exception('Failed to send email')
            
    except ObjectDoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return {
            'status': 'error',
            'message': f'User with ID {user_id} not found',
            'user_id': user_id
        }
    
    except Exception as exc:
        logger.error(f'Error sending welcome email to user {user_id}: {exc}')
        
        # Retry the task
        if self.request.retries < self.max_retries:
            raise self.retry(exc=exc, countdown=60 * (self.request.retries + 1))
        
        return {
            'status': 'error',
            'message': f'Failed to send welcome email after {self.max_retries} retries',
            'user_id': user_id,
            'error': str(exc)
        }


@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_password_reset_email(self, user_id: int, reset_token: str) -> Dict[str, Any]:
    """
    Send password reset email to user.
    
    Args:
        user_id: ID of the user
        reset_token: Password reset token
    
    Returns:
        Dict: Task result with status and message
    """
    try:
        user = User.objects.get(id=user_id)
        
        # Prepare email context
        context = {
            'user': user,
            'site': Site.objects.get_current(),
            'reset_url': reverse('authentification:password_reset_confirm', kwargs={
                'uidb64': user.pk,
                'token': reset_token
            }),
            'expiry_hours': getattr(settings, 'PASSWORD_RESET_TIMEOUT', 3600) // 3600
        }
        
        # Send email
        success = send_email_notification(
            template_name='accounts/emails/password_reset',
            context=context,
            to_email=user.email,
            subject=_('Password Reset Request - Ad-tlas')
        )
        
        if success:
            logger.info(f'Password reset email sent successfully to {user.email}')
            return {
                'status': 'success',
                'message': f'Password reset email sent to {user.email}',
                'user_id': user_id
            }
        else:
            raise Exception('Failed to send email')
            
    except ObjectDoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return {
            'status': 'error',
            'message': f'User with ID {user_id} not found',
            'user_id': user_id
        }
    
    except Exception as exc:
        logger.error(f'Error sending password reset email to user {user_id}: {exc}')
        
        # Retry the task
        if self.request.retries < self.max_retries:
            raise self.retry(exc=exc, countdown=60 * (self.request.retries + 1))
        
        return {
            'status': 'error',
            'message': f'Failed to send password reset email after {self.max_retries} retries',
            'user_id': user_id,
            'error': str(exc)
        }


@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_account_verification_email(self, user_id: int, verification_token: str) -> Dict[str, Any]:
    """
    Send account verification email to user.
    
    Args:
        user_id: ID of the user
        verification_token: Email verification token
    
    Returns:
        Dict: Task result with status and message
    """
    try:
        user = User.objects.get(id=user_id)
        
        # Prepare email context
        context = {
            'user': user,
            'site': Site.objects.get_current(),
            'verification_url': reverse('authentification:email_confirm', kwargs={
                'token': verification_token
            }),
            'expiry_hours': 24  # Verification links expire in 24 hours
        }
        
        # Send email
        success = send_email_notification(
            template_name='accounts/emails/email_verification',
            context=context,
            to_email=user.email,
            subject=_('Verify Your Email Address - Ad-tlas')
        )
        
        if success:
            logger.info(f'Verification email sent successfully to {user.email}')
            return {
                'status': 'success',
                'message': f'Verification email sent to {user.email}',
                'user_id': user_id
            }
        else:
            raise Exception('Failed to send email')
            
    except ObjectDoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return {
            'status': 'error',
            'message': f'User with ID {user_id} not found',
            'user_id': user_id
        }
    
    except Exception as exc:
        logger.error(f'Error sending verification email to user {user_id}: {exc}')
        
        # Retry the task
        if self.request.retries < self.max_retries:
            raise self.retry(exc=exc, countdown=60 * (self.request.retries + 1))
        
        return {
            'status': 'error',
            'message': f'Failed to send verification email after {self.max_retries} retries',
            'user_id': user_id,
            'error': str(exc)
        }


@shared_task
def cleanup_inactive_users(days_inactive: int = 365) -> Dict[str, Any]:
    """
    Clean up inactive user accounts.
    
    Args:
        days_inactive: Number of days of inactivity before cleanup
    
    Returns:
        Dict: Task result with cleanup statistics
    """
    try:
        cutoff_date = timezone.now() - timedelta(days=days_inactive)
        
        # Find inactive users
        inactive_users = User.objects.filter(
            is_active=False,
            last_login__lt=cutoff_date
        ).exclude(
            is_staff=True  # Don't delete staff accounts
        )
        
        # Count before deletion
        count = inactive_users.count()
        
        # Delete inactive users
        with transaction.atomic():
            deleted_users = []
            for user in inactive_users:
                deleted_users.append({
                    'id': user.id,
                    'email': user.email,
                    'last_login': user.last_login
                })
                user.delete()
        
        logger.info(f'Cleaned up {count} inactive users')
        
        return {
            'status': 'success',
            'message': f'Cleaned up {count} inactive users',
            'deleted_count': count,
            'deleted_users': deleted_users
        }
        
    except Exception as exc:
        logger.error(f'Error during user cleanup: {exc}')
        return {
            'status': 'error',
            'message': f'User cleanup failed: {str(exc)}',
            'deleted_count': 0
        }


@shared_task
def generate_user_reports() -> Dict[str, Any]:
    """
    Generate user analytics reports.
    
    Returns:
        Dict: Task result with report data
    """
    try:
        from .services import UserService
        
        user_service = UserService()
        statistics = user_service.get_user_statistics()
        
        # Additional analytics
        now = timezone.now()
        
        # Users registered this month
        month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        users_this_month = User.objects.filter(
            date_joined__gte=month_start
        ).count()
        
        # Users logged in this week
        week_start = now - timedelta(days=7)
        active_this_week = User.objects.filter(
            last_login__gte=week_start
        ).count()
        
        # Top users by activity
        try:
            from apps.activities.models import Activity
            top_users = User.objects.filter(
                activities__created_at__gte=week_start
            ).annotate(
                activity_count=models.Count('activities')
            ).order_by('-activity_count')[:10]
            
            top_users_data = [{
                'id': user.id,
                'email': user.email,
                'full_name': user.get_full_name(),
                'activity_count': user.activity_count
            } for user in top_users]
        except:
            top_users_data = []
        
        report_data = {
            **statistics,
            'users_this_month': users_this_month,
            'active_this_week': active_this_week,
            'top_users': top_users_data,
            'generated_at': now.isoformat()
        }
        
        logger.info('User reports generated successfully')
        
        return {
            'status': 'success',
            'message': 'User reports generated successfully',
            'report_data': report_data
        }
        
    except Exception as exc:
        logger.error(f'Error generating user reports: {exc}')
        return {
            'status': 'error',
            'message': f'Report generation failed: {str(exc)}'
        }


@shared_task(bind=True)
def bulk_user_operations(self, action: str, user_ids: List[int], **kwargs) -> Dict[str, Any]:
    """
    Perform bulk operations on users.
    
    Args:
        action: Action to perform (activate, deactivate, delete, export)
        user_ids: List of user IDs
        **kwargs: Additional parameters
    
    Returns:
        Dict: Task result with operation statistics
    """
    try:
        users = User.objects.filter(id__in=user_ids)
        total_users = users.count()
        processed_count = 0
        errors = []
        
        if action == 'activate':
            for user in users:
                try:
                    user.is_active = True
                    user.save()
                    processed_count += 1
                except Exception as e:
                    errors.append(f'User {user.id}: {str(e)}')
        
        elif action == 'deactivate':
            reason = kwargs.get('reason', 'Bulk deactivation')
            for user in users:
                try:
                    user.is_active = False
                    user.deactivated_at = timezone.now()
                    user.deactivation_reason = reason
                    user.save()
                    processed_count += 1
                except Exception as e:
                    errors.append(f'User {user.id}: {str(e)}')
        
        elif action == 'delete':
            with transaction.atomic():
                for user in users:
                    try:
                        if not user.is_staff:  # Don't delete staff
                            user.delete()
                            processed_count += 1
                        else:
                            errors.append(f'User {user.id}: Cannot delete staff user')
                    except Exception as e:
                        errors.append(f'User {user.id}: {str(e)}')
        
        elif action == 'export':
            from .services import ExportService
            export_service = ExportService()
            
            export_format = kwargs.get('format', 'csv')
            success, message, data = export_service.export_users(
                format=export_format,
                filters={'id__in': user_ids}
            )
            
            if success:
                processed_count = total_users
                return {
                    'status': 'success',
                    'message': f'Exported {total_users} users',
                    'processed_count': processed_count,
                    'total_count': total_users,
                    'export_data': data
                }
            else:
                errors.append(message)
        
        else:
            return {
                'status': 'error',
                'message': f'Unknown action: {action}'
            }
        
        logger.info(f'Bulk operation {action} completed: {processed_count}/{total_users} users processed')
        
        return {
            'status': 'success' if processed_count > 0 else 'error',
            'message': f'Processed {processed_count} of {total_users} users',
            'processed_count': processed_count,
            'total_count': total_users,
            'errors': errors
        }
        
    except Exception as exc:
        logger.error(f'Error in bulk user operation {action}: {exc}')
        return {
            'status': 'error',
            'message': f'Bulk operation failed: {str(exc)}',
            'processed_count': 0
        }


@shared_task
def sync_user_permissions() -> Dict[str, Any]:
    """
    Synchronize user permissions based on roles.
    
    Returns:
        Dict: Task result with sync statistics
    """
    try:
        from django.contrib.auth.models import Permission
        
        updated_count = 0
        errors = []
        
        # Define role permissions
        role_permissions = {
            'admin': Permission.objects.all(),
            'manager': Permission.objects.filter(
                content_type__app_label__in=['accounts', 'activities', 'notifications']
            ),
            'user': Permission.objects.filter(
                codename__in=['view_user', 'change_user']
            )
        }
        
        for role, permissions in role_permissions.items():
            users = User.objects.filter(role=role)
            
            for user in users:
                try:
                    user.user_permissions.set(permissions)
                    updated_count += 1
                except Exception as e:
                    errors.append(f'User {user.id}: {str(e)}')
        
        logger.info(f'User permissions synchronized: {updated_count} users updated')
        
        return {
            'status': 'success',
            'message': f'Synchronized permissions for {updated_count} users',
            'updated_count': updated_count,
            'errors': errors
        }
        
    except Exception as exc:
        logger.error(f'Error synchronizing user permissions: {exc}')
        return {
            'status': 'error',
            'message': f'Permission sync failed: {str(exc)}',
            'updated_count': 0
        }


@shared_task
def backup_user_data() -> Dict[str, Any]:
    """
    Backup user data to external storage.
    
    Returns:
        Dict: Task result with backup status
    """
    try:
        from .services import ExportService
        import os
        from django.core.files.storage import default_storage
        
        export_service = ExportService()
        
        # Export all users to JSON
        success, message, data = export_service.export_users(format='json')
        
        if success:
            # Save backup file
            timestamp = timezone.now().strftime('%Y%m%d_%H%M%S')
            filename = f'user_backup_{timestamp}.json'
            
            # Save to media/backups/
            backup_path = f'backups/{filename}'
            default_storage.save(backup_path, data)
            
            logger.info(f'User data backup completed: {filename}')
            
            return {
                'status': 'success',
                'message': f'User data backup completed',
                'backup_file': filename,
                'backup_path': backup_path
            }
        else:
            return {
                'status': 'error',
                'message': f'Backup failed: {message}'
            }
            
    except Exception as exc:
        logger.error(f'Error backing up user data: {exc}')
        return {
            'status': 'error',
            'message': f'Backup failed: {str(exc)}'
        }