# -*- coding: utf-8 -*-
"""
Campaigns App Tasks

This module contains Celery tasks for campaign-related operations.
"""

from celery import shared_task
from django.utils import timezone
from django.core.mail import send_mail
from django.conf import settings
from django.template.loader import render_to_string
from decimal import Decimal
import logging
import csv
import io

from .models import Campaign
from apps.advertisers.models import Advertiser

logger = logging.getLogger(__name__)


@shared_task(bind=True, max_retries=3)
def generate_campaign_report(self, campaign_id, report_type='performance'):
    """
    Generate campaign performance report.
    """
    try:
        campaign = Campaign.objects.get(id=campaign_id)
        logger.info(f"Generating {report_type} report for campaign {campaign.name}")
        
        # Generate report data
        report_data = {
            'campaign': campaign,
            'generated_at': timezone.now(),
            'report_type': report_type,
            'metrics': {
                'impressions': 0,  # Would be calculated from actual data
                'clicks': 0,
                'conversions': 0,
                'spend': Decimal('0.00'),
                'ctr': 0.0,
                'cpc': Decimal('0.00'),
                'conversion_rate': 0.0,
            }
        }
        
        # Save report or send via email
        send_campaign_report_email(campaign, report_data)
        
        logger.info(f"Successfully generated {report_type} report for campaign {campaign.name}")
        return f"Report generated for campaign {campaign.name}"
        
    except Campaign.DoesNotExist:
        logger.error(f"Campaign with ID {campaign_id} not found")
        raise
    except Exception as exc:
        logger.error(f"Error generating report for campaign {campaign_id}: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


@shared_task(bind=True, max_retries=3)
def monitor_campaign_budget(self, campaign_id):
    """
    Monitor campaign budget utilization and send alerts.
    """
    try:
        campaign = Campaign.objects.get(id=campaign_id)
        
        if campaign.status != 'active':
            return f"Campaign {campaign.name} is not active, skipping budget monitoring"
        
        # Calculate budget utilization (mock calculation)
        # In real implementation, this would query actual spend data
        total_spend = Decimal('0.00')  # Would be calculated from actual data
        budget_utilization = (total_spend / campaign.budget) * 100 if campaign.budget > 0 else 0
        
        logger.info(f"Budget utilization for campaign {campaign.name}: {budget_utilization:.2f}%")
        
        # Send alerts based on utilization thresholds
        if budget_utilization >= 90:
            send_budget_alert(campaign, 'critical', budget_utilization)
        elif budget_utilization >= 75:
            send_budget_alert(campaign, 'warning', budget_utilization)
        elif budget_utilization >= 50:
            send_budget_alert(campaign, 'info', budget_utilization)
        
        return f"Budget monitoring completed for campaign {campaign.name}"
        
    except Campaign.DoesNotExist:
        logger.error(f"Campaign with ID {campaign_id} not found")
        raise
    except Exception as exc:
        logger.error(f"Error monitoring budget for campaign {campaign_id}: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


@shared_task(bind=True, max_retries=3)
def optimize_campaign_performance(self, campaign_id):
    """
    Perform automated campaign optimization.
    """
    try:
        campaign = Campaign.objects.get(id=campaign_id)
        
        if campaign.status != 'active':
            return f"Campaign {campaign.name} is not active, skipping optimization"
        
        logger.info(f"Starting optimization for campaign {campaign.name}")
        
        # Perform optimization tasks
        optimizations = []
        
        # Example optimizations (would be based on actual performance data)
        # 1. Bid adjustments
        # 2. Keyword optimization
        # 3. Ad creative rotation
        # 4. Audience targeting refinement
        
        # Mock optimization results
        optimizations.append("Adjusted bids based on performance data")
        optimizations.append("Updated keyword targeting")
        optimizations.append("Rotated ad creatives")
        
        # Log optimization results
        for optimization in optimizations:
            logger.info(f"Campaign {campaign.name}: {optimization}")
        
        # Send optimization summary
        send_optimization_summary(campaign, optimizations)
        
        return f"Optimization completed for campaign {campaign.name}"
        
    except Campaign.DoesNotExist:
        logger.error(f"Campaign with ID {campaign_id} not found")
        raise
    except Exception as exc:
        logger.error(f"Error optimizing campaign {campaign_id}: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


@shared_task(bind=True, max_retries=3)
def check_campaign_expiry(self):
    """
    Check for campaigns that are expiring or have expired.
    """
    try:
        today = timezone.now().date()
        
        # Find campaigns expiring in 3 days
        expiring_soon = Campaign.objects.filter(
            status='active',
            end_date__lte=today + timezone.timedelta(days=3),
            end_date__gt=today
        )
        
        # Find campaigns that have expired
        expired = Campaign.objects.filter(
            status='active',
            end_date__lt=today
        )
        
        # Send expiry notifications
        for campaign in expiring_soon:
            send_expiry_notification(campaign, 'expiring_soon')
            logger.info(f"Sent expiry notification for campaign {campaign.name}")
        
        # Auto-complete expired campaigns
        for campaign in expired:
            campaign.status = 'completed'
            campaign.save()
            send_expiry_notification(campaign, 'expired')
            logger.info(f"Auto-completed expired campaign {campaign.name}")
        
        return f"Processed {len(expiring_soon)} expiring and {len(expired)} expired campaigns"
        
    except Exception as exc:
        logger.error(f"Error checking campaign expiry: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


@shared_task(bind=True, max_retries=3)
def import_campaigns_from_csv(self, csv_data, user_id):
    """
    Import campaigns from CSV data.
    """
    try:
        from django.contrib.auth import get_user_model
        User = get_user_model()
        
        user = User.objects.get(id=user_id)
        logger.info(f"Starting campaign import for user {user.username}")
        
        # Parse CSV data
        csv_file = io.StringIO(csv_data)
        reader = csv.DictReader(csv_file)
        
        imported_count = 0
        errors = []
        
        for row_num, row in enumerate(reader, start=2):
            try:
                # Validate required fields
                required_fields = ['name', 'advertiser_name', 'budget']
                for field in required_fields:
                    if not row.get(field):
                        raise ValueError(f"Missing required field: {field}")
                
                # Find advertiser
                advertiser = Advertiser.objects.filter(
                    name=row['advertiser_name'],
                    agency__users=user
                ).first()
                
                if not advertiser:
                    raise ValueError(f"Advertiser '{row['advertiser_name']}' not found")
                
                # Create campaign
                campaign = Campaign.objects.create(
                    name=row['name'],
                    description=row.get('description', ''),
                    advertiser=advertiser,
                    budget=Decimal(row['budget']),
                    status=row.get('status', 'draft')
                )
                
                imported_count += 1
                logger.info(f"Imported campaign: {campaign.name}")
                
            except Exception as e:
                error_msg = f"Row {row_num}: {str(e)}"
                errors.append(error_msg)
                logger.error(error_msg)
        
        # Send import summary
        send_import_summary(user, imported_count, errors)
        
        return f"Import completed: {imported_count} campaigns imported, {len(errors)} errors"
        
    except Exception as exc:
        logger.error(f"Error importing campaigns: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


@shared_task(bind=True, max_retries=3)
def sync_campaign_data(self, campaign_id):
    """
    Sync campaign data with external systems.
    """
    try:
        campaign = Campaign.objects.get(id=campaign_id)
        logger.info(f"Syncing data for campaign {campaign.name}")
        
        # Sync with external ad platforms
        # This would include:
        # - Google Ads API
        # - Facebook Ads API
        # - Other advertising platforms
        
        # Mock sync operations
        sync_results = {
            'google_ads': 'success',
            'facebook_ads': 'success',
            'analytics': 'success'
        }
        
        logger.info(f"Data sync completed for campaign {campaign.name}: {sync_results}")
        
        return f"Data sync completed for campaign {campaign.name}"
        
    except Campaign.DoesNotExist:
        logger.error(f"Campaign with ID {campaign_id} not found")
        raise
    except Exception as exc:
        logger.error(f"Error syncing data for campaign {campaign_id}: {str(exc)}")
        raise self.retry(exc=exc, countdown=60)


# Helper functions
def send_campaign_report_email(campaign, report_data):
    """
    Send campaign report via email.
    """
    try:
        agency_users = campaign.advertiser.agency.users.all()
        recipient_emails = [user.email for user in agency_users if user.email]
        
        if recipient_emails:
            context = {
                'campaign': campaign,
                'report_data': report_data,
            }
            
            html_message = render_to_string('emails/campaign_report.html', context)
            
            send_mail(
                subject=f"[Ad-tlas] Campaign Report: {campaign.name}",
                message='',
                html_message=html_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipient_emails,
                fail_silently=True
            )
    except Exception as e:
        logger.error(f"Failed to send campaign report email: {str(e)}")


def send_budget_alert(campaign, alert_type, utilization):
    """
    Send budget utilization alert.
    """
    try:
        agency_users = campaign.advertiser.agency.users.all()
        recipient_emails = [user.email for user in agency_users if user.email]
        
        if recipient_emails:
            context = {
                'campaign': campaign,
                'alert_type': alert_type,
                'utilization': utilization,
            }
            
            html_message = render_to_string('emails/budget_alert.html', context)
            
            send_mail(
                subject=f"[Ad-tlas] Budget Alert: {campaign.name}",
                message='',
                html_message=html_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipient_emails,
                fail_silently=True
            )
    except Exception as e:
        logger.error(f"Failed to send budget alert email: {str(e)}")


def send_optimization_summary(campaign, optimizations):
    """
    Send optimization summary email.
    """
    try:
        agency_users = campaign.advertiser.agency.users.all()
        recipient_emails = [user.email for user in agency_users if user.email]
        
        if recipient_emails:
            context = {
                'campaign': campaign,
                'optimizations': optimizations,
            }
            
            html_message = render_to_string('emails/optimization_summary.html', context)
            
            send_mail(
                subject=f"[Ad-tlas] Optimization Summary: {campaign.name}",
                message='',
                html_message=html_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipient_emails,
                fail_silently=True
            )
    except Exception as e:
        logger.error(f"Failed to send optimization summary email: {str(e)}")


def send_expiry_notification(campaign, notification_type):
    """
    Send campaign expiry notification.
    """
    try:
        agency_users = campaign.advertiser.agency.users.all()
        recipient_emails = [user.email for user in agency_users if user.email]
        
        if recipient_emails:
            context = {
                'campaign': campaign,
                'notification_type': notification_type,
            }
            
            html_message = render_to_string('emails/campaign_expiry.html', context)
            
            send_mail(
                subject=f"[Ad-tlas] Campaign Expiry: {campaign.name}",
                message='',
                html_message=html_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipient_emails,
                fail_silently=True
            )
    except Exception as e:
        logger.error(f"Failed to send expiry notification email: {str(e)}")


def send_import_summary(user, imported_count, errors):
    """
    Send campaign import summary email.
    """
    try:
        if user.email:
            context = {
                'user': user,
                'imported_count': imported_count,
                'errors': errors,
            }
            
            html_message = render_to_string('emails/import_summary.html', context)
            
            send_mail(
                subject="[Ad-tlas] Campaign Import Summary",
                message='',
                html_message=html_message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=[user.email],
                fail_silently=True
            )
    except Exception as e:
        logger.error(f"Failed to send import summary email: {str(e)}")