"""Views for Reporting and Analytics app."""

from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.urls import reverse_lazy
from django.db.models import Q, Count, Avg, Sum, Max, Min
from django.utils import timezone
from datetime import datetime, timedelta, date
from rest_framework import viewsets, status, permissions
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
import json
from decimal import Decimal

from .models import (
    AnalyticsRegion,
    AnalyticsTarget,
    SfrAnalytics,
    MarketShare,
    VerificationRecord,
    PredictionModel,
    SfrPrediction,
    AdbreakPrediction,
    ActivityLog,
    RealTimeAdbreak,
)
from .serializers import (
    AnalyticsRegionSerializer,
    AnalyticsTargetSerializer,
    SfrAnalyticsSerializer,
    MarketShareSerializer,
    VerificationRecordSerializer,
    PredictionModelSerializer,
    SfrPredictionSerializer,
    AdbreakPredictionSerializer,
    ActivityLogSerializer,
    RealTimeAdbreakSerializer,
)
from .filters import (
    SfrAnalyticsFilter,
    MarketShareFilter,
    VerificationRecordFilter,
    SfrPredictionFilter,
    AdbreakPredictionFilter,
    ActivityLogFilter,
    RealTimeAdbreakFilter,
)


# API ViewSets
class AnalyticsRegionViewSet(viewsets.ModelViewSet):
    """ViewSet for managing analytics regions."""
    
    queryset = AnalyticsRegion.objects.all()
    serializer_class = AnalyticsRegionSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['name', 'code', 'country']
    ordering_fields = ['name', 'code', 'created_at']
    ordering = ['name']


class AnalyticsTargetViewSet(viewsets.ModelViewSet):
    """ViewSet for managing analytics targets."""
    
    queryset = AnalyticsTarget.objects.all()
    serializer_class = AnalyticsTargetSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['name', 'code', 'description']
    ordering_fields = ['name', 'code', 'created_at']
    ordering = ['name']


class SfrAnalyticsViewSet(viewsets.ModelViewSet):
    """ViewSet for SFR analytics data."""
    
    queryset = SfrAnalytics.objects.select_related('channel', 'region', 'target')
    serializer_class = SfrAnalyticsSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = SfrAnalyticsFilter
    search_fields = ['channel__name', 'sfr_channel_name', 'indicator']
    ordering_fields = ['measurement_date', 'measurement_time', 'value', 'created_at']
    ordering = ['-measurement_date', '-measurement_time']
    
    @action(detail=False, methods=['get'])
    def summary(self, request):
        """Get analytics summary statistics."""
        queryset = self.filter_queryset(self.get_queryset())
        
        summary_data = {
            'total_records': queryset.count(),
            'date_range': {
                'start': queryset.aggregate(Min('measurement_date'))['measurement_date__min'],
                'end': queryset.aggregate(Max('measurement_date'))['measurement_date__max'],
            },
            'channels': queryset.values('channel__name').distinct().count(),
            'regions': queryset.values('region__name').distinct().count(),
            'targets': queryset.values('target__name').distinct().count(),
            'indicators': queryset.values('indicator').annotate(
                count=Count('id'),
                avg_value=Avg('value')
            ).order_by('indicator'),
        }
        
        return Response(summary_data)
    
    @action(detail=False, methods=['get'])
    def trends(self, request):
        """Get analytics trends over time."""
        queryset = self.filter_queryset(self.get_queryset())
        
        # Group by date and calculate averages
        trends = queryset.values('measurement_date', 'indicator').annotate(
            avg_value=Avg('value'),
            count=Count('id')
        ).order_by('measurement_date', 'indicator')
        
        return Response(list(trends))
    
    @action(detail=False, methods=['get'])
    def top_performers(self, request):
        """Get top performing channels by indicator."""
        queryset = self.filter_queryset(self.get_queryset())
        indicator = request.query_params.get('indicator', 'rating')
        limit = int(request.query_params.get('limit', 10))
        
        top_performers = queryset.filter(indicator=indicator).values(
            'channel__name', 'channel__id'
        ).annotate(
            avg_value=Avg('value'),
            max_value=Max('value'),
            count=Count('id')
        ).order_by('-avg_value')[:limit]
        
        return Response(list(top_performers))


class MarketShareViewSet(viewsets.ModelViewSet):
    """ViewSet for market share data."""
    
    queryset = MarketShare.objects.select_related('channel', 'region', 'target')
    serializer_class = MarketShareSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = MarketShareFilter
    search_fields = ['channel__name']
    ordering_fields = ['measurement_date', 'market_share_percentage', 'ranking']
    ordering = ['-measurement_date', '-market_share_percentage']
    
    @action(detail=False, methods=['get'])
    def rankings(self, request):
        """Get channel rankings by market share."""
        queryset = self.filter_queryset(self.get_queryset())
        measurement_date = request.query_params.get('date')
        
        if measurement_date:
            try:
                date_obj = datetime.strptime(measurement_date, '%Y-%m-%d').date()
                queryset = queryset.filter(measurement_date=date_obj)
            except ValueError:
                return Response(
                    {'error': 'Invalid date format. Use YYYY-MM-DD.'},
                    status=status.HTTP_400_BAD_REQUEST
                )
        else:
            # Get latest date
            latest_date = queryset.aggregate(Max('measurement_date'))['measurement_date__max']
            if latest_date:
                queryset = queryset.filter(measurement_date=latest_date)
        
        rankings = queryset.order_by('ranking').values(
            'channel__name', 'market_share_percentage', 'ranking',
            'total_users', 'channel_users', 'region__name', 'target__name'
        )
        
        return Response(list(rankings))


class VerificationRecordViewSet(viewsets.ModelViewSet):
    """ViewSet for verification records."""
    
    queryset = VerificationRecord.objects.select_related(
        'campaign', 'advertiser', 'verified_by'
    )
    serializer_class = VerificationRecordSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = VerificationRecordFilter
    search_fields = ['spot_id', 'network_name', 'zone_name']
    ordering_fields = ['broadcast_date', 'created_at', 'status']
    ordering = ['-broadcast_date', '-created_at']
    
    @action(detail=True, methods=['post'])
    def verify(self, request, pk=None):
        """Mark a verification record as verified."""
        record = self.get_object()
        record.status = 'verified'
        record.verified_by = request.user
        record.verified_at = timezone.now()
        record.save()
        
        return Response({'status': 'verified'})
    
    @action(detail=True, methods=['post'])
    def reject(self, request, pk=None):
        """Mark a verification record as failed."""
        record = self.get_object()
        record.status = 'failed'
        record.error_message = request.data.get('error_message', '')
        record.save()
        
        return Response({'status': 'failed'})
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """Get verification statistics."""
        queryset = self.filter_queryset(self.get_queryset())
        
        stats = {
            'total': queryset.count(),
            'by_status': queryset.values('status').annotate(
                count=Count('id')
            ).order_by('status'),
            'by_network': queryset.values('network_name').annotate(
                count=Count('id'),
                verified_count=Count('id', filter=Q(status='verified')),
                failed_count=Count('id', filter=Q(status='failed'))
            ).order_by('-count')[:10],
            'recent_activity': queryset.filter(
                created_at__gte=timezone.now() - timedelta(days=7)
            ).count(),
        }
        
        return Response(stats)


class PredictionModelViewSet(viewsets.ModelViewSet):
    """ViewSet for prediction models."""
    
    queryset = PredictionModel.objects.all()
    serializer_class = PredictionModelSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['name', 'description', 'algorithm']
    ordering_fields = ['name', 'created_at', 'accuracy_score']
    ordering = ['-created_at']
    
    @action(detail=True, methods=['post'])
    def activate(self, request, pk=None):
        """Activate a prediction model."""
        model = self.get_object()
        model.is_active = True
        model.save()
        
        return Response({'status': 'activated'})
    
    @action(detail=True, methods=['post'])
    def deactivate(self, request, pk=None):
        """Deactivate a prediction model."""
        model = self.get_object()
        model.is_active = False
        model.save()
        
        return Response({'status': 'deactivated'})


class SfrPredictionViewSet(viewsets.ModelViewSet):
    """ViewSet for SFR predictions."""
    
    queryset = SfrPrediction.objects.select_related(
        'model', 'channel', 'region', 'target'
    )
    serializer_class = SfrPredictionSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = SfrPredictionFilter
    search_fields = ['channel__name', 'indicator']
    ordering_fields = ['prediction_date', 'prediction_time', 'predicted_value']
    ordering = ['-prediction_date', '-prediction_time']
    
    @action(detail=False, methods=['get'])
    def accuracy_report(self, request):
        """Get prediction accuracy report."""
        queryset = self.filter_queryset(self.get_queryset()).filter(
            actual_value__isnull=False
        )
        
        accuracy_data = []
        for prediction in queryset:
            accuracy = prediction.accuracy
            if accuracy is not None:
                accuracy_data.append({
                    'id': prediction.id,
                    'channel': prediction.channel.name,
                    'indicator': prediction.indicator,
                    'prediction_date': prediction.prediction_date,
                    'predicted_value': prediction.predicted_value,
                    'actual_value': prediction.actual_value,
                    'accuracy': accuracy,
                    'model': prediction.model.name,
                })
        
        # Calculate overall statistics
        if accuracy_data:
            accuracies = [item['accuracy'] for item in accuracy_data]
            stats = {
                'total_predictions': len(accuracy_data),
                'average_accuracy': sum(accuracies) / len(accuracies),
                'min_accuracy': min(accuracies),
                'max_accuracy': max(accuracies),
                'predictions': accuracy_data,
            }
        else:
            stats = {
                'total_predictions': 0,
                'average_accuracy': None,
                'min_accuracy': None,
                'max_accuracy': None,
                'predictions': [],
            }
        
        return Response(stats)


class AdbreakPredictionViewSet(viewsets.ModelViewSet):
    """ViewSet for ad break predictions."""
    
    queryset = AdbreakPrediction.objects.select_related('model', 'channel')
    serializer_class = AdbreakPredictionSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = AdbreakPredictionFilter
    search_fields = ['channel__name']
    ordering_fields = ['prediction_datetime', 'confidence_score']
    ordering = ['-prediction_datetime']


class ActivityLogViewSet(viewsets.ReadOnlyModelViewSet):
    """ViewSet for activity logs (read-only)."""
    
    queryset = ActivityLog.objects.select_related('user')
    serializer_class = ActivityLogSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = ActivityLogFilter
    search_fields = ['description', 'user__username']
    ordering_fields = ['activity_date', 'created_at']
    ordering = ['-created_at']


class RealTimeAdbreakViewSet(viewsets.ModelViewSet):
    """ViewSet for real-time ad breaks."""
    
    queryset = RealTimeAdbreak.objects.select_related('channel')
    serializer_class = RealTimeAdbreakSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = RealTimeAdbreakFilter
    search_fields = ['channel__name']
    ordering_fields = ['start_time', 'status']
    ordering = ['-start_time']
    
    @action(detail=True, methods=['post'])
    def start(self, request, pk=None):
        """Start an ad break."""
        adbreak = self.get_object()
        adbreak.status = 'started'
        adbreak.start_time = timezone.now()
        adbreak.save()
        
        return Response({'status': 'started', 'start_time': adbreak.start_time})
    
    @action(detail=True, methods=['post'])
    def complete(self, request, pk=None):
        """Complete an ad break."""
        adbreak = self.get_object()
        adbreak.status = 'completed'
        adbreak.end_time = timezone.now()
        
        # Calculate duration
        if adbreak.start_time:
            duration = adbreak.end_time - adbreak.start_time
            adbreak.duration_seconds = int(duration.total_seconds())
        
        adbreak.save()
        
        return Response({
            'status': 'completed',
            'end_time': adbreak.end_time,
            'duration_seconds': adbreak.duration_seconds
        })


# Django Template Views
class AnalyticsDashboardView(LoginRequiredMixin, ListView):
    """Analytics dashboard view."""
    
    template_name = 'reporting/dashboard.html'
    context_object_name = 'recent_analytics'
    
    def get_queryset(self):
        return SfrAnalytics.objects.select_related(
            'channel', 'region', 'target'
        ).order_by('-measurement_date', '-measurement_time')[:50]
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get summary statistics
        today = timezone.now().date()
        week_ago = today - timedelta(days=7)
        
        context.update({
            'total_analytics': SfrAnalytics.objects.count(),
            'recent_analytics_count': SfrAnalytics.objects.filter(
                measurement_date__gte=week_ago
            ).count(),
            'total_verifications': VerificationRecord.objects.count(),
            'pending_verifications': VerificationRecord.objects.filter(
                status='pending'
            ).count(),
            'active_models': PredictionModel.objects.filter(
                is_active=True
            ).count(),
            'recent_predictions': SfrPrediction.objects.filter(
                prediction_date__gte=week_ago
            ).count(),
        })
        
        return context


class SfrAnalyticsListView(LoginRequiredMixin, ListView):
    """SFR Analytics list view."""
    
    model = SfrAnalytics
    template_name = 'reporting/sfr_analytics_list.html'
    context_object_name = 'analytics'
    paginate_by = 50
    
    def get_queryset(self):
        return SfrAnalytics.objects.select_related(
            'channel', 'region', 'target'
        ).order_by('-measurement_date', '-measurement_time')


class VerificationRecordListView(LoginRequiredMixin, ListView):
    """Verification records list view."""
    
    model = VerificationRecord
    template_name = 'reporting/verification_list.html'
    context_object_name = 'verifications'
    paginate_by = 50
    
    def get_queryset(self):
        return VerificationRecord.objects.select_related(
            'campaign', 'advertiser', 'verified_by'
        ).order_by('-broadcast_date', '-created_at')


class PredictionModelListView(LoginRequiredMixin, ListView):
    """Prediction models list view."""
    
    model = PredictionModel
    template_name = 'reporting/prediction_models_list.html'
    context_object_name = 'models'
    paginate_by = 20
    
    def get_queryset(self):
        return PredictionModel.objects.order_by('-created_at')


class ReportsView(LoginRequiredMixin, ListView):
    """Reports generation view."""
    
    template_name = 'reporting/reports.html'
    context_object_name = 'recent_activity'
    
    def get_queryset(self):
        return ActivityLog.objects.select_related('user').order_by('-created_at')[:20]
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Add report generation options
        context.update({
            'available_reports': [
                {'name': 'Analytics Summary', 'type': 'analytics_summary'},
                {'name': 'Market Share Report', 'type': 'market_share'},
                {'name': 'Verification Report', 'type': 'verification'},
                {'name': 'Prediction Accuracy', 'type': 'prediction_accuracy'},
                {'name': 'Activity Log', 'type': 'activity_log'},
            ]
        })
        
        return context


# API Functions
def generate_report(request):
    """Generate custom reports based on parameters."""
    if request.method != 'POST':
        return JsonResponse({'error': 'POST method required'}, status=405)
    
    try:
        data = json.loads(request.body)
        report_type = data.get('type')
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        
        if not report_type:
            return JsonResponse({'error': 'Report type is required'}, status=400)
        
        # Parse dates
        if start_date:
            start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
        if end_date:
            end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
        
        # Generate report based on type
        if report_type == 'analytics_summary':
            report_data = generate_analytics_summary_report(start_date, end_date)
        elif report_type == 'market_share':
            report_data = generate_market_share_report(start_date, end_date)
        elif report_type == 'verification':
            report_data = generate_verification_report(start_date, end_date)
        elif report_type == 'prediction_accuracy':
            report_data = generate_prediction_accuracy_report(start_date, end_date)
        else:
            return JsonResponse({'error': 'Invalid report type'}, status=400)
        
        return JsonResponse(report_data)
    
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)


def generate_analytics_summary_report(start_date=None, end_date=None):
    """Generate analytics summary report."""
    queryset = SfrAnalytics.objects.all()
    
    if start_date:
        queryset = queryset.filter(measurement_date__gte=start_date)
    if end_date:
        queryset = queryset.filter(measurement_date__lte=end_date)
    
    summary = {
        'total_records': queryset.count(),
        'date_range': {
            'start': start_date,
            'end': end_date,
        },
        'by_indicator': list(queryset.values('indicator').annotate(
            count=Count('id'),
            avg_value=Avg('value'),
            max_value=Max('value'),
            min_value=Min('value')
        ).order_by('indicator')),
        'by_channel': list(queryset.values('channel__name').annotate(
            count=Count('id'),
            avg_value=Avg('value')
        ).order_by('-avg_value')[:10]),
    }
    
    return summary


def generate_market_share_report(start_date=None, end_date=None):
    """Generate market share report."""
    queryset = MarketShare.objects.all()
    
    if start_date:
        queryset = queryset.filter(measurement_date__gte=start_date)
    if end_date:
        queryset = queryset.filter(measurement_date__lte=end_date)
    
    report = {
        'total_records': queryset.count(),
        'date_range': {
            'start': start_date,
            'end': end_date,
        },
        'top_channels': list(queryset.values('channel__name').annotate(
            avg_share=Avg('market_share_percentage'),
            avg_ranking=Avg('ranking')
        ).order_by('-avg_share')[:10]),
        'by_region': list(queryset.values('region__name').annotate(
            total_users=Sum('total_users'),
            avg_share=Avg('market_share_percentage')
        ).order_by('-total_users')),
    }
    
    return report


def generate_verification_report(start_date=None, end_date=None):
    """Generate verification report."""
    queryset = VerificationRecord.objects.all()
    
    if start_date:
        queryset = queryset.filter(broadcast_date__gte=start_date)
    if end_date:
        queryset = queryset.filter(broadcast_date__lte=end_date)
    
    report = {
        'total_records': queryset.count(),
        'date_range': {
            'start': start_date,
            'end': end_date,
        },
        'by_status': list(queryset.values('status').annotate(
            count=Count('id')
        ).order_by('status')),
        'by_network': list(queryset.values('network_name').annotate(
            count=Count('id'),
            verified_count=Count('id', filter=Q(status='verified')),
            failed_count=Count('id', filter=Q(status='failed'))
        ).order_by('-count')[:10]),
    }
    
    return report


def generate_prediction_accuracy_report(start_date=None, end_date=None):
    """Generate prediction accuracy report."""
    queryset = SfrPrediction.objects.filter(actual_value__isnull=False)
    
    if start_date:
        queryset = queryset.filter(prediction_date__gte=start_date)
    if end_date:
        queryset = queryset.filter(prediction_date__lte=end_date)
    
    # Calculate accuracies
    predictions_with_accuracy = []
    for prediction in queryset:
        accuracy = prediction.accuracy
        if accuracy is not None:
            predictions_with_accuracy.append({
                'model': prediction.model.name,
                'channel': prediction.channel.name,
                'indicator': prediction.indicator,
                'accuracy': accuracy,
            })
    
    # Calculate statistics
    if predictions_with_accuracy:
        accuracies = [p['accuracy'] for p in predictions_with_accuracy]
        avg_accuracy = sum(accuracies) / len(accuracies)
        
        # Group by model
        model_stats = {}
        for p in predictions_with_accuracy:
            model = p['model']
            if model not in model_stats:
                model_stats[model] = []
            model_stats[model].append(p['accuracy'])
        
        model_summary = []
        for model, accs in model_stats.items():
            model_summary.append({
                'model': model,
                'count': len(accs),
                'avg_accuracy': sum(accs) / len(accs),
                'min_accuracy': min(accs),
                'max_accuracy': max(accs),
            })
    else:
        avg_accuracy = None
        model_summary = []
    
    report = {
        'total_predictions': len(predictions_with_accuracy),
        'average_accuracy': avg_accuracy,
        'date_range': {
            'start': start_date,
            'end': end_date,
        },
        'by_model': model_summary,
    }
    
    return report