"""Views for Jingles app."""

import os
import json
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional

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.http import JsonResponse, HttpResponse, Http404
from django.views.generic import (
    ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.urls import reverse_lazy
from django.utils import timezone
from django.db.models import Q, Count, Sum, Avg, Max, Min
from django.core.paginator import Paginator
from django.core.files.storage import default_storage
from django.conf import settings
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

from rest_framework import viewsets, status, permissions
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser, FormParser
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter

from .models import (
    JingleCategory,
    JingleType,
    Jingle,
    JinglePlaylist,
    JinglePlaylistItem,
    JingleSchedule,
)
from .serializers import (
    JingleCategorySerializer,
    JingleTypeSerializer,
    JingleSerializer,
    JingleDetailSerializer,
    JinglePlaylistSerializer,
    JinglePlaylistDetailSerializer,
    JinglePlaylistItemSerializer,
    JingleScheduleSerializer,
)
from .filters import (
    JingleFilter,
    JinglePlaylistFilter,
    JingleScheduleFilter,
)
from apps.channels.models import Channel


# =============================================================================
# DRF ViewSets for API
# =============================================================================

class JingleCategoryViewSet(viewsets.ModelViewSet):
    """ViewSet for JingleCategory model."""
    
    queryset = JingleCategory.objects.all()
    serializer_class = JingleCategorySerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'sort_order', 'created_at']
    ordering = ['sort_order', 'name']
    
    @action(detail=False, methods=['get'])
    def active(self, request):
        """Get only active categories."""
        categories = self.queryset.filter(is_active=True)
        serializer = self.get_serializer(categories, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['post'])
    def toggle_active(self, request, pk=None):
        """Toggle active status of a category."""
        category = self.get_object()
        category.is_active = not category.is_active
        category.save()
        
        return Response({
            'status': 'success',
            'is_active': category.is_active,
            'message': f'Category {"activated" if category.is_active else "deactivated"}'
        })
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """Get category statistics."""
        stats = self.queryset.aggregate(
            total_categories=Count('id'),
            active_categories=Count('id', filter=Q(is_active=True)),
            total_jingles=Count('jingles'),
        )
        
        # Get top categories by jingle count
        top_categories = self.queryset.annotate(
            jingle_count=Count('jingles')
        ).order_by('-jingle_count')[:5]
        
        stats['top_categories'] = JingleCategorySerializer(
            top_categories, many=True
        ).data
        
        return Response(stats)


class JingleTypeViewSet(viewsets.ModelViewSet):
    """ViewSet for JingleType model."""
    
    queryset = JingleType.objects.all()
    serializer_class = JingleTypeSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = ['name', 'description', 'usage']
    ordering_fields = ['name', 'usage', 'created_at']
    ordering = ['name']
    
    @action(detail=False, methods=['get'])
    def by_usage(self, request):
        """Get types grouped by usage."""
        usage_groups = {}
        for choice in JingleType.USAGE_CHOICES:
            usage_code, usage_name = choice
            types = self.queryset.filter(usage=usage_code, is_active=True)
            usage_groups[usage_code] = {
                'name': usage_name,
                'types': JingleTypeSerializer(types, many=True).data
            }
        
        return Response(usage_groups)


class JingleViewSet(viewsets.ModelViewSet):
    """ViewSet for Jingle model."""
    
    queryset = Jingle.objects.select_related(
        'channel', 'category', 'jingle_type', 'uploaded_by', 'approved_by'
    )
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = JingleFilter
    search_fields = [
        'name', 'description', 'tags',
        'channel__name', 'category__name', 'jingle_type__name'
    ]
    ordering_fields = [
        'name', 'created_at', 'duration_seconds',
        'play_count', 'last_played', 'priority'
    ]
    ordering = ['-created_at']
    
    def get_serializer_class(self):
        """Return appropriate serializer based on action."""
        if self.action == 'retrieve':
            return JingleDetailSerializer
        return JingleSerializer
    
    def get_queryset(self):
        """Filter queryset based on user permissions."""
        queryset = super().get_queryset()
        
        # Filter by channel access if user has limited permissions
        if not self.request.user.is_superuser:
            # Assuming user has access to specific channels
            user_channels = Channel.objects.filter(
                # Add your channel access logic here
            )
            queryset = queryset.filter(channel__in=user_channels)
        
        return queryset.filter(is_deleted=False)
    
    def perform_create(self, serializer):
        """Set uploaded_by when creating a jingle."""
        serializer.save(uploaded_by=self.request.user)
    
    @action(detail=False, methods=['get'])
    def available(self, request):
        """Get available jingles for playback."""
        jingles = self.get_queryset().filter(
            is_active=True,
            status='approved'
        )
        
        # Filter by date availability
        today = timezone.now().date()
        jingles = jingles.filter(
            Q(start_date__isnull=True) | Q(start_date__lte=today),
            Q(end_date__isnull=True) | Q(end_date__gte=today)
        )
        
        channel_id = request.query_params.get('channel')
        if channel_id:
            jingles = jingles.filter(channel_id=channel_id)
        
        serializer = self.get_serializer(jingles, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['post'])
    def approve(self, request, pk=None):
        """Approve a jingle."""
        jingle = self.get_object()
        jingle.status = 'approved'
        jingle.approved_by = request.user
        jingle.approved_at = timezone.now()
        jingle.save()
        
        return Response({
            'status': 'success',
            'message': 'Jingle approved successfully'
        })
    
    @action(detail=True, methods=['post'])
    def reject(self, request, pk=None):
        """Reject a jingle."""
        jingle = self.get_object()
        jingle.status = 'rejected'
        jingle.save()
        
        return Response({
            'status': 'success',
            'message': 'Jingle rejected'
        })
    
    @action(detail=True, methods=['post'])
    def play(self, request, pk=None):
        """Record a play event for the jingle."""
        jingle = self.get_object()
        jingle.increment_play_count()
        
        return Response({
            'status': 'success',
            'play_count': jingle.play_count,
            'last_played': jingle.last_played
        })
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """Get jingle statistics."""
        queryset = self.get_queryset()
        
        stats = queryset.aggregate(
            total_jingles=Count('id'),
            approved_jingles=Count('id', filter=Q(status='approved')),
            pending_jingles=Count('id', filter=Q(status='pending')),
            total_duration=Sum('duration_seconds'),
            total_plays=Sum('play_count'),
            avg_duration=Avg('duration_seconds'),
        )
        
        # Most played jingles
        most_played = queryset.order_by('-play_count')[:5]
        stats['most_played'] = JingleSerializer(most_played, many=True).data
        
        # Recent uploads
        recent = queryset.order_by('-created_at')[:5]
        stats['recent_uploads'] = JingleSerializer(recent, many=True).data
        
        return Response(stats)
    
    @action(detail=False, methods=['post'])
    def bulk_approve(self, request):
        """Bulk approve jingles."""
        jingle_ids = request.data.get('jingle_ids', [])
        if not jingle_ids:
            return Response(
                {'error': 'No jingle IDs provided'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        updated = self.get_queryset().filter(
            id__in=jingle_ids,
            status='pending'
        ).update(
            status='approved',
            approved_by=request.user,
            approved_at=timezone.now()
        )
        
        return Response({
            'status': 'success',
            'updated_count': updated,
            'message': f'{updated} jingles approved'
        })
    
    @action(detail=False, methods=['get'])
    def export(self, request):
        """Export jingles data."""
        queryset = self.filter_queryset(self.get_queryset())
        
        export_data = []
        for jingle in queryset:
            export_data.append({
                'id': jingle.id,
                'name': jingle.name,
                'channel': jingle.channel.name,
                'category': jingle.category.name if jingle.category else '',
                'type': jingle.jingle_type.name if jingle.jingle_type else '',
                'duration': jingle.get_duration_display(),
                'status': jingle.get_status_display(),
                'play_count': jingle.play_count,
                'created_at': jingle.created_at.isoformat(),
            })
        
        return Response({
            'data': export_data,
            'total_count': len(export_data)
        })


class JinglePlaylistViewSet(viewsets.ModelViewSet):
    """ViewSet for JinglePlaylist model."""
    
    queryset = JinglePlaylist.objects.select_related(
        'channel', 'created_by'
    ).prefetch_related('playlist_items__jingle')
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = JinglePlaylistFilter
    search_fields = ['name', 'description', 'channel__name']
    ordering_fields = ['name', 'created_at']
    ordering = ['name']
    
    def get_serializer_class(self):
        """Return appropriate serializer based on action."""
        if self.action == 'retrieve':
            return JinglePlaylistDetailSerializer
        return JinglePlaylistSerializer
    
    def perform_create(self, serializer):
        """Set created_by when creating a playlist."""
        serializer.save(created_by=self.request.user)
    
    @action(detail=True, methods=['post'])
    def add_jingle(self, request, pk=None):
        """Add a jingle to the playlist."""
        playlist = self.get_object()
        jingle_id = request.data.get('jingle_id')
        order = request.data.get('order')
        
        if not jingle_id:
            return Response(
                {'error': 'jingle_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            jingle = Jingle.objects.get(id=jingle_id)
        except Jingle.DoesNotExist:
            return Response(
                {'error': 'Jingle not found'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        # Check if jingle is already in playlist
        if playlist.playlist_items.filter(jingle=jingle).exists():
            return Response(
                {'error': 'Jingle already in playlist'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Set order if not provided
        if order is None:
            max_order = playlist.playlist_items.aggregate(
                max_order=Max('order')
            )['max_order'] or 0
            order = max_order + 1
        
        # Create playlist item
        playlist_item = JinglePlaylistItem.objects.create(
            playlist=playlist,
            jingle=jingle,
            order=order
        )
        
        serializer = JinglePlaylistItemSerializer(playlist_item)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    
    @action(detail=True, methods=['delete'])
    def remove_jingle(self, request, pk=None):
        """Remove a jingle from the playlist."""
        playlist = self.get_object()
        jingle_id = request.data.get('jingle_id')
        
        if not jingle_id:
            return Response(
                {'error': 'jingle_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            playlist_item = playlist.playlist_items.get(jingle_id=jingle_id)
            playlist_item.delete()
            return Response({'status': 'success'})
        except JinglePlaylistItem.DoesNotExist:
            return Response(
                {'error': 'Jingle not in playlist'},
                status=status.HTTP_404_NOT_FOUND
            )
    
    @action(detail=True, methods=['post'])
    def reorder(self, request, pk=None):
        """Reorder jingles in the playlist."""
        playlist = self.get_object()
        item_orders = request.data.get('item_orders', [])
        
        if not item_orders:
            return Response(
                {'error': 'item_orders is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Update orders
        for item_data in item_orders:
            try:
                item = playlist.playlist_items.get(id=item_data['id'])
                item.order = item_data['order']
                item.save()
            except (JinglePlaylistItem.DoesNotExist, KeyError):
                continue
        
        return Response({'status': 'success'})
    
    @action(detail=True, methods=['get'])
    def next_jingle(self, request, pk=None):
        """Get the next jingle to play from the playlist."""
        playlist = self.get_object()
        current_jingle_id = request.query_params.get('current_jingle')
        
        current_jingle = None
        if current_jingle_id:
            try:
                current_jingle = Jingle.objects.get(id=current_jingle_id)
            except Jingle.DoesNotExist:
                pass
        
        next_jingle = playlist.get_next_jingle(current_jingle)
        
        if next_jingle:
            serializer = JingleSerializer(next_jingle)
            return Response(serializer.data)
        else:
            return Response({'message': 'No next jingle available'})


class JinglePlaylistItemViewSet(viewsets.ModelViewSet):
    """ViewSet for JinglePlaylistItem model."""
    
    queryset = JinglePlaylistItem.objects.select_related(
        'playlist', 'playlist__channel', 'jingle'
    )
    serializer_class = JinglePlaylistItemSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, OrderingFilter]
    ordering_fields = ['order', 'created_at']
    ordering = ['playlist', 'order']


class JingleScheduleViewSet(viewsets.ModelViewSet):
    """ViewSet for JingleSchedule model."""
    
    queryset = JingleSchedule.objects.select_related(
        'channel', 'playlist', 'created_by'
    )
    serializer_class = JingleScheduleSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = JingleScheduleFilter
    search_fields = ['name', 'channel__name', 'playlist__name']
    ordering_fields = ['name', 'priority', 'created_at']
    ordering = ['priority', 'name']
    
    def perform_create(self, serializer):
        """Set created_by when creating a schedule."""
        serializer.save(created_by=self.request.user)
    
    @action(detail=False, methods=['get'])
    def active_now(self, request):
        """Get schedules that are currently active."""
        active_schedules = []
        for schedule in self.get_queryset():
            if schedule.is_active_now():
                active_schedules.append(schedule)
        
        serializer = self.get_serializer(active_schedules, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'])
    def check_active(self, request, pk=None):
        """Check if a specific schedule is currently active."""
        schedule = self.get_object()
        is_active = schedule.is_active_now()
        
        return Response({
            'is_active': is_active,
            'next_execution': schedule.get_next_execution_time()
        })


# =============================================================================
# Django Template Views
# =============================================================================

class JingleListView(LoginRequiredMixin, ListView):
    """List view for jingles."""
    
    model = Jingle
    template_name = 'jingles/jingle_list.html'
    context_object_name = 'jingles'
    paginate_by = 20
    
    def get_queryset(self):
        """Filter jingles based on search and filters."""
        queryset = Jingle.objects.select_related(
            'channel', 'category', 'jingle_type'
        ).filter(is_deleted=False)
        
        # Search
        search = self.request.GET.get('search')
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) |
                Q(description__icontains=search) |
                Q(tags__icontains=search)
            )
        
        # Filters
        channel = self.request.GET.get('channel')
        if channel:
            queryset = queryset.filter(channel_id=channel)
        
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        category = self.request.GET.get('category')
        if category:
            queryset = queryset.filter(category_id=category)
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        """Add additional context data."""
        context = super().get_context_data(**kwargs)
        context['channels'] = Channel.objects.filter(is_active=True)
        context['categories'] = JingleCategory.objects.filter(is_active=True)
        context['status_choices'] = Jingle.STATUS_CHOICES
        context['search'] = self.request.GET.get('search', '')
        context['selected_channel'] = self.request.GET.get('channel', '')
        context['selected_status'] = self.request.GET.get('status', '')
        context['selected_category'] = self.request.GET.get('category', '')
        return context


class JingleDetailView(LoginRequiredMixin, DetailView):
    """Detail view for a jingle."""
    
    model = Jingle
    template_name = 'jingles/jingle_detail.html'
    context_object_name = 'jingle'
    
    def get_queryset(self):
        """Include related objects."""
        return Jingle.objects.select_related(
            'channel', 'category', 'jingle_type',
            'uploaded_by', 'approved_by'
        ).prefetch_related('playlists')


class JingleCreateView(LoginRequiredMixin, CreateView):
    """Create view for jingles."""
    
    model = Jingle
    template_name = 'jingles/jingle_form.html'
    fields = [
        'name', 'description', 'channel', 'category',
        'jingle_type', 'file', 'tags', 'priority',
        'start_date', 'end_date'
    ]
    success_url = reverse_lazy('jingles:jingle-list')
    
    def form_valid(self, form):
        """Set uploaded_by when creating."""
        form.instance.uploaded_by = self.request.user
        messages.success(self.request, 'Jingle uploaded successfully!')
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        """Add additional context data."""
        context = super().get_context_data(**kwargs)
        context['title'] = 'Upload New Jingle'
        return context


class JingleUpdateView(LoginRequiredMixin, UpdateView):
    """Update view for jingles."""
    
    model = Jingle
    template_name = 'jingles/jingle_form.html'
    fields = [
        'name', 'description', 'category', 'jingle_type',
        'tags', 'priority', 'start_date', 'end_date',
        'status', 'quality', 'is_active'
    ]
    
    def get_success_url(self):
        """Redirect to detail view after update."""
        return reverse_lazy('jingles:jingle-detail', kwargs={'pk': self.object.pk})
    
    def form_valid(self, form):
        """Add success message."""
        messages.success(self.request, 'Jingle updated successfully!')
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        """Add additional context data."""
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.name}'
        return context


class JingleDeleteView(LoginRequiredMixin, DeleteView):
    """Delete view for jingles."""
    
    model = Jingle
    template_name = 'jingles/jingle_confirm_delete.html'
    success_url = reverse_lazy('jingles:jingle-list')
    
    def delete(self, request, *args, **kwargs):
        """Soft delete the jingle."""
        self.object = self.get_object()
        self.object.is_deleted = True
        self.object.is_active = False
        self.object.save()
        messages.success(request, 'Jingle deleted successfully!')
        return redirect(self.success_url)


class PlaylistListView(LoginRequiredMixin, ListView):
    """List view for playlists."""
    
    model = JinglePlaylist
    template_name = 'jingles/playlist_list.html'
    context_object_name = 'playlists'
    paginate_by = 20
    
    def get_queryset(self):
        """Filter playlists."""
        queryset = JinglePlaylist.objects.select_related(
            'channel', 'created_by'
        ).annotate(
            jingle_count=Count('playlist_items')
        )
        
        channel = self.request.GET.get('channel')
        if channel:
            queryset = queryset.filter(channel_id=channel)
        
        return queryset.order_by('name')
    
    def get_context_data(self, **kwargs):
        """Add additional context data."""
        context = super().get_context_data(**kwargs)
        context['channels'] = Channel.objects.filter(is_active=True)
        context['selected_channel'] = self.request.GET.get('channel', '')
        return context


class PlaylistDetailView(LoginRequiredMixin, DetailView):
    """Detail view for a playlist."""
    
    model = JinglePlaylist
    template_name = 'jingles/playlist_detail.html'
    context_object_name = 'playlist'
    
    def get_queryset(self):
        """Include related objects."""
        return JinglePlaylist.objects.select_related(
            'channel', 'created_by'
        ).prefetch_related(
            'playlist_items__jingle',
            'playlist_items__jingle__category'
        )


# =============================================================================
# AJAX and Utility Views
# =============================================================================

@login_required
@require_http_methods(["POST"])
def approve_jingle(request, jingle_id):
    """AJAX view to approve a jingle."""
    try:
        jingle = get_object_or_404(Jingle, id=jingle_id)
        jingle.status = 'approved'
        jingle.approved_by = request.user
        jingle.approved_at = timezone.now()
        jingle.save()
        
        return JsonResponse({
            'status': 'success',
            'message': 'Jingle approved successfully'
        })
    except Exception as e:
        return JsonResponse({
            'status': 'error',
            'message': str(e)
        }, status=500)


@login_required
@require_http_methods(["POST"])
def reject_jingle(request, jingle_id):
    """AJAX view to reject a jingle."""
    try:
        jingle = get_object_or_404(Jingle, id=jingle_id)
        jingle.status = 'rejected'
        jingle.save()
        
        return JsonResponse({
            'status': 'success',
            'message': 'Jingle rejected'
        })
    except Exception as e:
        return JsonResponse({
            'status': 'error',
            'message': str(e)
        }, status=500)


@login_required
def jingle_dashboard(request):
    """Dashboard view for jingles overview."""
    # Statistics
    total_jingles = Jingle.objects.filter(is_deleted=False).count()
    approved_jingles = Jingle.objects.filter(
        status='approved', is_deleted=False
    ).count()
    pending_jingles = Jingle.objects.filter(
        status='pending', is_deleted=False
    ).count()
    
    # Recent uploads
    recent_jingles = Jingle.objects.select_related(
        'channel', 'uploaded_by'
    ).filter(is_deleted=False).order_by('-created_at')[:5]
    
    # Most played
    most_played = Jingle.objects.select_related(
        'channel'
    ).filter(
        is_deleted=False, play_count__gt=0
    ).order_by('-play_count')[:5]
    
    # Channel statistics
    channel_stats = Channel.objects.annotate(
        jingle_count=Count('jingles', filter=Q(jingles__is_deleted=False))
    ).filter(is_active=True).order_by('-jingle_count')[:5]
    
    context = {
        'total_jingles': total_jingles,
        'approved_jingles': approved_jingles,
        'pending_jingles': pending_jingles,
        'recent_jingles': recent_jingles,
        'most_played': most_played,
        'channel_stats': channel_stats,
    }
    
    return render(request, 'jingles/dashboard.html', context)


@login_required
def get_jingles_by_category(request):
    """AJAX view to get jingles by category."""
    category_id = request.GET.get('category_id')
    channel_id = request.GET.get('channel_id')
    
    jingles = Jingle.objects.filter(
        is_active=True,
        status='approved',
        is_deleted=False
    )
    
    if category_id:
        jingles = jingles.filter(category_id=category_id)
    
    if channel_id:
        jingles = jingles.filter(channel_id=channel_id)
    
    jingle_data = []
    for jingle in jingles:
        jingle_data.append({
            'id': jingle.id,
            'name': jingle.name,
            'duration': jingle.get_duration_display(),
            'file_url': jingle.get_file_url(),
        })
    
    return JsonResponse({'jingles': jingle_data})


@login_required
def playlist_preview(request, playlist_id):
    """Preview a playlist with all its jingles."""
    playlist = get_object_or_404(
        JinglePlaylist.objects.prefetch_related(
            'playlist_items__jingle'
        ),
        id=playlist_id
    )
    
    items = playlist.playlist_items.filter(
        is_active=True,
        jingle__is_active=True,
        jingle__status='approved'
    ).order_by('order')
    
    context = {
        'playlist': playlist,
        'items': items,
        'total_duration': playlist.get_total_duration(),
    }
    
    return render(request, 'jingles/playlist_preview.html', context)