# -*- coding: utf-8 -*-
"""
Campaigns Views Module

This module contains all view classes and functions for the campaigns app.
Includes list views, detail views, create/update forms, and API endpoints.
"""

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import (
    ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.db.models import Q, Sum, Avg, Count
from django.utils import timezone
from django.http import JsonResponse
from django.core.paginator import Paginator

from .models import Campaign, CampaignChannelSchedule, CampaignPerformance
from .forms import CampaignForm, CampaignChannelScheduleForm


class CampaignListView(LoginRequiredMixin, ListView):
    """
    List view for campaigns with filtering and search.
    """
    model = Campaign
    template_name = 'campaigns/campaign_list.html'
    context_object_name = 'campaigns'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = Campaign.objects.select_related('advertiser').prefetch_related(
            'geographic_zones', 'channels'
        )
        
        # Filter by status
        status = self.request.GET.get('status')
        if status:
            queryset = queryset.filter(status=status)
        
        # Filter by campaign type
        campaign_type = self.request.GET.get('type')
        if campaign_type:
            queryset = queryset.filter(campaign_type=campaign_type)
        
        # Filter by advertiser
        advertiser = self.request.GET.get('advertiser')
        if advertiser:
            queryset = queryset.filter(advertiser_id=advertiser)
        
        # Search functionality
        search = self.request.GET.get('search')
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) |
                Q(description__icontains=search) |
                Q(advertiser__name__icontains=search)
            )
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['status_choices'] = Campaign.CAMPAIGN_STATUS
        context['type_choices'] = Campaign.CAMPAIGN_TYPES
        context['current_status'] = self.request.GET.get('status', '')
        context['current_type'] = self.request.GET.get('type', '')
        context['current_search'] = self.request.GET.get('search', '')
        
        # Add summary statistics
        context['total_campaigns'] = Campaign.objects.count()
        context['active_campaigns'] = Campaign.objects.filter(status='active').count()
        context['total_budget'] = Campaign.objects.aggregate(
            total=Sum('total_budget')
        )['total'] or 0
        
        return context


class CampaignDetailView(LoginRequiredMixin, DetailView):
    """
    Detail view for individual campaigns.
    """
    model = Campaign
    template_name = 'campaigns/campaign_detail.html'
    context_object_name = 'campaign'
    
    def get_queryset(self):
        return Campaign.objects.select_related('advertiser').prefetch_related(
            'geographic_zones', 'channels', 'channel_schedules__channel',
            'performance_records'
        )
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        campaign = self.object
        
        # Get channel schedules
        context['channel_schedules'] = campaign.channel_schedules.select_related(
            'channel'
        ).all()
        
        # Get recent performance data
        context['recent_performance'] = campaign.performance_records.order_by(
            '-date'
        )[:30]
        
        # Calculate performance metrics
        performance_data = campaign.performance_records.aggregate(
            total_impressions=Sum('impressions'),
            total_spend=Sum('spend'),
            avg_cpm=Avg('cpm'),
            total_spots=Sum('spots_aired')
        )
        context['performance_summary'] = performance_data
        
        # Calculate daily averages
        days_running = (timezone.now().date() - campaign.start_date.date()).days + 1
        if days_running > 0:
            context['daily_averages'] = {
                'impressions': (performance_data['total_impressions'] or 0) / days_running,
                'spend': (performance_data['total_spend'] or 0) / days_running,
                'spots': (performance_data['total_spots'] or 0) / days_running
            }
        
        return context


class CampaignCreateView(LoginRequiredMixin, CreateView):
    """
    Create view for new campaigns.
    """
    model = Campaign
    form_class = CampaignForm
    template_name = 'campaigns/campaign_form.html'
    success_url = reverse_lazy('campaigns:list')
    
    def form_valid(self, form):
        messages.success(
            self.request,
            _('Campaign "{}" has been created successfully.').format(
                form.instance.name
            )
        )
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = _('Create New Campaign')
        context['submit_text'] = _('Create Campaign')
        return context


class CampaignUpdateView(LoginRequiredMixin, UpdateView):
    """
    Update view for existing campaigns.
    """
    model = Campaign
    form_class = CampaignForm
    template_name = 'campaigns/campaign_form.html'
    
    def get_success_url(self):
        return reverse_lazy('campaigns:detail', kwargs={'pk': self.object.pk})
    
    def form_valid(self, form):
        messages.success(
            self.request,
            _('Campaign "{}" has been updated successfully.').format(
                form.instance.name
            )
        )
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = _('Edit Campaign: {}').format(self.object.name)
        context['submit_text'] = _('Update Campaign')
        return context


class CampaignDeleteView(LoginRequiredMixin, DeleteView):
    """
    Delete view for campaigns.
    """
    model = Campaign
    template_name = 'campaigns/campaign_confirm_delete.html'
    success_url = reverse_lazy('campaigns:list')
    
    def delete(self, request, *args, **kwargs):
        campaign = self.get_object()
        messages.success(
            request,
            _('Campaign "{}" has been deleted successfully.').format(
                campaign.name
            )
        )
        return super().delete(request, *args, **kwargs)


@login_required
def campaign_dashboard(request):
    """
    Dashboard view showing campaign overview and statistics.
    """
    # Get campaign statistics
    total_campaigns = Campaign.objects.count()
    active_campaigns = Campaign.objects.filter(status='active').count()
    pending_campaigns = Campaign.objects.filter(status='pending').count()
    completed_campaigns = Campaign.objects.filter(status='completed').count()
    
    # Get budget statistics
    budget_stats = Campaign.objects.aggregate(
        total_budget=Sum('total_budget'),
        total_spend=Sum('total_spend')
    )
    
    # Get recent campaigns
    recent_campaigns = Campaign.objects.select_related('advertiser').order_by(
        '-created_at'
    )[:10]
    
    # Get campaigns ending soon
    ending_soon = Campaign.objects.filter(
        status='active',
        end_date__lte=timezone.now() + timezone.timedelta(days=7)
    ).order_by('end_date')[:5]
    
    # Get top performing campaigns
    top_performers = Campaign.objects.filter(
        status__in=['active', 'completed']
    ).order_by('-total_impressions')[:5]
    
    context = {
        'total_campaigns': total_campaigns,
        'active_campaigns': active_campaigns,
        'pending_campaigns': pending_campaigns,
        'completed_campaigns': completed_campaigns,
        'budget_stats': budget_stats,
        'recent_campaigns': recent_campaigns,
        'ending_soon': ending_soon,
        'top_performers': top_performers,
    }
    
    return render(request, 'campaigns/dashboard.html', context)


@login_required
def campaign_activate(request, pk):
    """
    Activate a campaign.
    """
    campaign = get_object_or_404(Campaign, pk=pk)
    
    if campaign.can_be_activated():
        campaign.status = 'active'
        campaign.save()
        messages.success(
            request,
            _('Campaign "{}" has been activated.').format(campaign.name)
        )
    else:
        messages.error(
            request,
            _('Campaign "{}" cannot be activated. Please check the requirements.').format(
                campaign.name
            )
        )
    
    return redirect('campaigns:detail', pk=pk)


@login_required
def campaign_pause(request, pk):
    """
    Pause a campaign.
    """
    campaign = get_object_or_404(Campaign, pk=pk)
    
    if campaign.status == 'active':
        campaign.status = 'paused'
        campaign.save()
        messages.success(
            request,
            _('Campaign "{}" has been paused.').format(campaign.name)
        )
    else:
        messages.error(
            request,
            _('Only active campaigns can be paused.')
        )
    
    return redirect('campaigns:detail', pk=pk)


@login_required
def campaign_performance_data(request, pk):
    """
    AJAX endpoint for campaign performance chart data.
    """
    campaign = get_object_or_404(Campaign, pk=pk)
    
    # Get performance data for the last 30 days
    performance_data = campaign.performance_records.filter(
        date__gte=timezone.now().date() - timezone.timedelta(days=30)
    ).order_by('date')
    
    data = {
        'dates': [p.date.strftime('%Y-%m-%d') for p in performance_data],
        'impressions': [p.impressions for p in performance_data],
        'spend': [float(p.spend) for p in performance_data],
        'spots': [p.spots_aired for p in performance_data],
        'cpm': [float(p.cpm) if p.cpm else 0 for p in performance_data]
    }
    
    return JsonResponse(data)


@login_required
def campaign_clone(request, pk):
    """
    Clone an existing campaign.
    """
    original_campaign = get_object_or_404(Campaign, pk=pk)
    
    # Create a copy of the campaign
    cloned_campaign = Campaign.objects.get(pk=pk)
    cloned_campaign.pk = None  # This will create a new instance
    cloned_campaign.name = f"{original_campaign.name} (Copy)"
    cloned_campaign.status = 'draft'
    cloned_campaign.total_impressions = 0
    cloned_campaign.total_spend = 0
    cloned_campaign.save()
    
    # Copy geographic zones
    cloned_campaign.geographic_zones.set(original_campaign.geographic_zones.all())
    
    # Copy channel schedules
    for schedule in original_campaign.channel_schedules.all():
        CampaignChannelSchedule.objects.create(
            campaign=cloned_campaign,
            channel=schedule.channel,
            start_time=schedule.start_time,
            end_time=schedule.end_time,
            days_of_week=schedule.days_of_week,
            spots_per_day=schedule.spots_per_day,
            channel_budget=schedule.channel_budget
        )
    
    messages.success(
        request,
        _('Campaign "{}" has been cloned successfully.').format(
            cloned_campaign.name
        )
    )
    
    return redirect('campaigns:detail', pk=cloned_campaign.pk)