# -*- coding: utf-8 -*-
"""
Celery tasks for the activities app.

This module contains asynchronous tasks for activity processing,
analytics generation, and maintenance operations.
"""

from celery import shared_task
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.core.mail import send_mail
from django.conf import settings
from datetime import timedelta
import logging

User = get_user_model()
logger = logging.getLogger(__name__)


@shared_task(bind=True, max_retries=3)
def log_user_activity(self, user_id, action, content_type_id=None, object_id=None, metadata=None):
    """
    Asynchronously log user activity.
    
    Args:
        user_id: User ID
        action: Activity action string
        content_type_id: Content type ID (optional)
        object_id: Object ID (optional)
        metadata: Additional metadata dict (optional)
    
    Returns:
        Activity ID if successful, None otherwise
    """
    try:
        from .services import ActivityService
        from django.contrib.contenttypes.models import ContentType
        
        user = User.objects.get(pk=user_id)
        
        content_object = None
        if content_type_id and object_id:
            content_type = ContentType.objects.get(pk=content_type_id)
            content_object = content_type.get_object_for_this_type(pk=object_id)
        
        activity = ActivityService.log_activity(
            user=user,
            action=action,
            content_object=content_object,
            metadata=metadata or {}
        )
        
        if activity:
            logger.info(
                f'Activity logged asynchronously: {user.email} - {action}'
            )
            return activity.id
        
        return None
        
    except User.DoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return None
    except Exception as exc:
        logger.error(
            f'Error logging activity for user {user_id}: {str(exc)}'
        )
        # Retry the task
        raise self.retry(exc=exc, countdown=60)


@shared_task
def generate_daily_activity_report():
    """
    Generate daily activity report and send to administrators.
    
    Returns:
        Boolean indicating success
    """
    try:
        from .services import ActivityAnalyticsService
        from django.template.loader import render_to_string
        
        # Get platform stats for the last 24 hours
        stats = ActivityAnalyticsService.get_platform_stats(days=1)
        
        # Get engagement report
        engagement_report = ActivityAnalyticsService.get_user_engagement_report(days=1)
        
        # Prepare email content
        context = {
            'stats': stats,
            'engagement_report': engagement_report,
            'date': timezone.now().date(),
        }
        
        subject = f'Daily Activity Report - {timezone.now().strftime("%Y-%m-%d")}'
        
        # Render email template (assuming template exists)
        try:
            message = render_to_string('activities/emails/daily_report.html', context)
        except:
            # Fallback to plain text if template doesn't exist
            message = f"""
            Daily Activity Report - {context['date']}
            
            Platform Statistics:
            - Total Activities: {stats['total_activities']}
            - Active Users: {stats['active_users']}
            - Engagement Rate: {stats['engagement_rate']:.2f}%
            - Avg Activities per User: {stats['avg_activities_per_user']:.2f}
            
            Top Actions:
            {chr(10).join([f"- {action['action']}: {action['count']}" for action in stats['top_actions'][:5]])}
            
            Engagement Summary:
            - High Engagement Users: {engagement_report['engagement_summary']['high_count']}
            - Medium Engagement Users: {engagement_report['engagement_summary']['medium_count']}
            - Low Engagement Users: {engagement_report['engagement_summary']['low_count']}
            """
        
        # Get admin emails
        admin_emails = list(
            User.objects.filter(is_superuser=True, is_active=True)
            .values_list('email', flat=True)
        )
        
        if admin_emails:
            send_mail(
                subject=subject,
                message=message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=admin_emails,
                html_message=message if '<html>' in message else None,
                fail_silently=False
            )
            
            logger.info(
                f'Daily activity report sent to {len(admin_emails)} administrators'
            )
        
        return True
        
    except Exception as e:
        logger.error(f'Error generating daily activity report: {str(e)}')
        return False


@shared_task
def cleanup_old_activities(days=90):
    """
    Clean up old activity records.
    
    Args:
        days: Number of days to keep (default: 90)
    
    Returns:
        Number of deleted records
    """
    try:
        from .services import ActivityCleanupService
        
        deleted_count = ActivityCleanupService.cleanup_old_activities(days=days)
        
        logger.info(
            f'Activity cleanup completed. Deleted {deleted_count} old records.'
        )
        
        return deleted_count
        
    except Exception as e:
        logger.error(f'Error during activity cleanup: {str(e)}')
        return 0


@shared_task
def archive_old_activities(days=365):
    """
    Archive old activities to external storage.
    
    Args:
        days: Number of days to keep in main database (default: 365)
    
    Returns:
        Path to archived file or None
    """
    try:
        from .services import ActivityCleanupService
        
        archive_path = ActivityCleanupService.archive_activities(days=days)
        
        if archive_path:
            logger.info(f'Activities archived to: {archive_path}')
        else:
            logger.info('No activities to archive')
        
        return archive_path
        
    except Exception as e:
        logger.error(f'Error during activity archiving: {str(e)}')
        return None


@shared_task
def generate_user_activity_summary(user_id, days=30):
    """
    Generate activity summary for a specific user.
    
    Args:
        user_id: User ID
        days: Number of days to analyze (default: 30)
    
    Returns:
        Activity summary dict
    """
    try:
        from .services import ActivityService
        
        user = User.objects.get(pk=user_id)
        stats = ActivityService.get_activity_stats(user, days=days)
        
        logger.info(
            f'Activity summary generated for user {user.email}'
        )
        
        return stats
        
    except User.DoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return None
    except Exception as e:
        logger.error(
            f'Error generating activity summary for user {user_id}: {str(e)}'
        )
        return None


@shared_task
def detect_suspicious_activity():
    """
    Detect suspicious user activity patterns.
    
    Returns:
        List of suspicious activity alerts
    """
    try:
        from .models import Activity
        from django.db.models import Count
        
        alerts = []
        
        # Check for users with excessive activity in short time
        one_hour_ago = timezone.now() - timedelta(hours=1)
        
        suspicious_users = (
            Activity.objects.filter(timestamp__gte=one_hour_ago)
            .values('user__email')
            .annotate(activity_count=Count('id'))
            .filter(activity_count__gt=100)  # More than 100 activities per hour
        )
        
        for user_data in suspicious_users:
            alerts.append({
                'type': 'excessive_activity',
                'user_email': user_data['user__email'],
                'activity_count': user_data['activity_count'],
                'timeframe': '1 hour',
                'timestamp': timezone.now().isoformat()
            })
        
        # Check for unusual login patterns
        twenty_four_hours_ago = timezone.now() - timedelta(hours=24)
        
        unusual_logins = (
            Activity.objects.filter(
                timestamp__gte=twenty_four_hours_ago,
                action='user_login'
            )
            .values('user__email', 'ip_address')
            .annotate(ip_count=Count('ip_address', distinct=True))
            .filter(ip_count__gt=5)  # More than 5 different IPs in 24 hours
        )
        
        for login_data in unusual_logins:
            alerts.append({
                'type': 'unusual_login_pattern',
                'user_email': login_data['user__email'],
                'ip_count': login_data['ip_count'],
                'timeframe': '24 hours',
                'timestamp': timezone.now().isoformat()
            })
        
        # Send alerts to administrators if any found
        if alerts:
            admin_emails = list(
                User.objects.filter(is_superuser=True, is_active=True)
                .values_list('email', flat=True)
            )
            
            if admin_emails:
                subject = f'Suspicious Activity Alert - {len(alerts)} incidents detected'
                message = f"""
                Suspicious Activity Report
                
                {len(alerts)} suspicious activity patterns detected:
                
                {chr(10).join([f"- {alert['type']}: {alert['user_email']} ({alert.get('activity_count', alert.get('ip_count'))})" for alert in alerts])}
                
                Please review these activities and take appropriate action.
                """
                
                send_mail(
                    subject=subject,
                    message=message,
                    from_email=settings.DEFAULT_FROM_EMAIL,
                    recipient_list=admin_emails,
                    fail_silently=False
                )
                
                logger.warning(
                    f'Suspicious activity alert sent: {len(alerts)} incidents'
                )
        
        return alerts
        
    except Exception as e:
        logger.error(f'Error detecting suspicious activity: {str(e)}')
        return []


@shared_task
def update_user_activity_cache(user_id):
    """
    Update cached activity data for a specific user.
    
    Args:
        user_id: User ID
    
    Returns:
        Boolean indicating success
    """
    try:
        from .services import ActivityService
        from django.core.cache import cache
        
        user = User.objects.get(pk=user_id)
        
        # Clear existing cache
        cache_keys = [
            f'user_activities_{user_id}',
            f'activity_stats_{user_id}_30',
            f'activity_stats_{user_id}_7',
        ]
        cache.delete_many(cache_keys)
        
        # Warm up cache with fresh data
        ActivityService.get_user_activities(user, limit=50)
        ActivityService.get_activity_stats(user, days=30)
        ActivityService.get_activity_stats(user, days=7)
        
        logger.info(f'Activity cache updated for user {user.email}')
        
        return True
        
    except User.DoesNotExist:
        logger.error(f'User with ID {user_id} not found')
        return False
    except Exception as e:
        logger.error(
            f'Error updating activity cache for user {user_id}: {str(e)}'
        )
        return False


@shared_task
def export_activity_data_async(user_id=None, start_date=None, end_date=None, format='csv', email_to=None):
    """
    Export activity data asynchronously and optionally email the result.
    
    Args:
        user_id: Specific user ID to export (optional)
        start_date: Start date string (optional)
        end_date: End date string (optional)
        format: Export format ('csv' or 'json')
        email_to: Email address to send the export (optional)
    
    Returns:
        Path to exported file
    """
    try:
        from .services import ActivityAnalyticsService
        from datetime import datetime
        import os
        from django.conf import settings
        
        user = None
        if user_id:
            user = User.objects.get(pk=user_id)
        
        # Parse dates
        start_dt = None
        end_dt = None
        
        if start_date:
            start_dt = datetime.fromisoformat(start_date)
        
        if end_date:
            end_dt = datetime.fromisoformat(end_date)
        
        # Export data
        exported_data = ActivityAnalyticsService.export_activity_data(
            user=user,
            start_date=start_dt,
            end_date=end_dt,
            format=format
        )
        
        # Save to file
        export_dir = os.path.join(settings.MEDIA_ROOT, 'exports', 'activities')
        os.makedirs(export_dir, exist_ok=True)
        
        filename = f'activity_export_{timezone.now().strftime("%Y%m%d_%H%M%S")}.{format}'
        file_path = os.path.join(export_dir, filename)
        
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(exported_data)
        
        # Email the export if requested
        if email_to:
            subject = f'Activity Data Export - {filename}'
            message = f"""
            Your activity data export is ready.
            
            Export Details:
            - Format: {format.upper()}
            - User: {user.email if user else 'All users'}
            - Date Range: {start_date or 'All time'} to {end_date or 'Now'}
            - File: {filename}
            
            The export file has been generated and is available for download.
            """
            
            send_mail(
                subject=subject,
                message=message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=[email_to],
                fail_silently=False
            )
        
        logger.info(f'Activity data exported to: {file_path}')
        
        return file_path
        
    except Exception as e:
        logger.error(f'Error exporting activity data: {str(e)}')
        return None