"""Channels Views

This module contains views for channel management functionality.
It includes both API ViewSets for REST operations and traditional
Django views for web interface.

Views:
    - ChannelViewSet: API operations for channels
    - ChannelZoneViewSet: API operations for channel zones
    - ChannelCodecViewSet: API operations for codec configurations
    - JingleViewSet: API operations for jingles
    - DayTimeViewSet: API operations for time slots
    - Traditional views for web interface
    - AJAX endpoints for dynamic functionality

Features:
- CRUD operations for all channel-related models
- Filtering and search capabilities
- Bulk operations support
- File upload handling for logos and jingles
- Statistics and analytics
- Export functionality
"""

import json
import logging
from datetime import datetime, timedelta
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.core.paginator import Paginator
from django.db.models import Q, Count, Avg, Sum
from django.utils import timezone
from django.conf import settings

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 Channel, ChannelZone, ChannelCodec, Jingle, DayTime
from .serializers import (
    ChannelSerializer, ChannelDetailSerializer, ChannelZoneSerializer,
    ChannelCodecSerializer, JingleSerializer, DayTimeSerializer,
    ChannelWithZonesSerializer, ChannelStatsSerializer,
    BulkChannelSerializer, JingleUploadSerializer
)
from .filters import (
    ChannelFilter, ChannelZoneFilter, ChannelCodecFilter,
    JingleFilter, DayTimeFilter
)
from apps.core.permissions import IsOwnerOrReadOnly
from apps.core.utils import generate_export_response


logger = logging.getLogger(__name__)


# ============================================================================
# API ViewSets
# ============================================================================

class ChannelViewSet(viewsets.ModelViewSet):
    """ViewSet for Channel model.
    
    Provides CRUD operations for TV channels with advanced
    filtering, search, and bulk operations.
    
    Features:
    - Full CRUD operations
    - Advanced filtering by provider, region, status
    - Search by name, code, description
    - Bulk operations (activate, deactivate, delete)
    - Statistics and analytics
    - Export functionality
    - Logo upload handling
    """
    
    queryset = Channel.objects.all()
    serializer_class = ChannelSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = ChannelFilter
    search_fields = ['name', 'channel_code', 'description', 'provider']
    ordering_fields = ['name', 'channel_code', 'provider', 'created_at']
    ordering = ['name']
    parser_classes = [MultiPartParser, FormParser]
    
    def get_serializer_class(self):
        """Return appropriate serializer based on action."""
        if self.action == 'retrieve':
            return ChannelDetailSerializer
        elif self.action == 'with_zones':
            return ChannelWithZonesSerializer
        elif self.action == 'statistics':
            return ChannelStatsSerializer
        elif self.action in ['bulk_activate', 'bulk_deactivate']:
            return BulkChannelSerializer
        return ChannelSerializer
    
    def perform_create(self, serializer):
        """Set creator when creating a channel."""
        serializer.save(created_by=self.request.user)
    
    def perform_update(self, serializer):
        """Set updater when updating a channel."""
        serializer.save(updated_by=self.request.user)
    
    @action(detail=True, methods=['get'])
    def zones(self, request, pk=None):
        """Get all zones for a specific channel."""
        channel = self.get_object()
        zones = channel.zones.filter(status='active')
        serializer = ChannelZoneSerializer(zones, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'])
    def codecs(self, request, pk=None):
        """Get all codec configurations for a specific channel."""
        channel = self.get_object()
        codecs = channel.codecs.filter(status='active')
        serializer = ChannelCodecSerializer(codecs, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'])
    def jingles(self, request, pk=None):
        """Get all jingles for a specific channel."""
        channel = self.get_object()
        jingles = channel.jingles.filter(status='active')
        serializer = JingleSerializer(jingles, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """Get channel statistics and analytics."""
        stats = {
            'total_channels': Channel.objects.count(),
            'active_channels': Channel.objects.filter(status='active').count(),
            'inactive_channels': Channel.objects.filter(status='inactive').count(),
            'by_provider': Channel.objects.values('provider').annotate(
                count=Count('id')
            ).order_by('-count'),
            'hd_channels': Channel.objects.filter(is_hd=True).count(),
            'uhd_channels': Channel.objects.filter(is_4k=True).count(),
            'total_zones': ChannelZone.objects.filter(status='active').count(),
            'total_jingles': Jingle.objects.filter(status='active').count(),
        }
        return Response(stats)
    
    @action(detail=False, methods=['post'])
    def bulk_activate(self, request):
        """Bulk activate channels."""
        serializer = BulkChannelSerializer(data=request.data)
        if serializer.is_valid():
            channel_ids = serializer.validated_data['channel_ids']
            updated = Channel.objects.filter(
                id__in=channel_ids
            ).update(
                status='active',
                updated_by=request.user,
                updated_at=timezone.now()
            )
            return Response({
                'message': f'Successfully activated {updated} channels',
                'updated_count': updated
            })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=False, methods=['post'])
    def bulk_deactivate(self, request):
        """Bulk deactivate channels."""
        serializer = BulkChannelSerializer(data=request.data)
        if serializer.is_valid():
            channel_ids = serializer.validated_data['channel_ids']
            updated = Channel.objects.filter(
                id__in=channel_ids
            ).update(
                status='inactive',
                updated_by=request.user,
                updated_at=timezone.now()
            )
            return Response({
                'message': f'Successfully deactivated {updated} channels',
                'updated_count': updated
            })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=False, methods=['get'])
    def export(self, request):
        """Export channels data."""
        queryset = self.filter_queryset(self.get_queryset())
        return generate_export_response(
            queryset,
            'channels',
            ['name', 'channel_code', 'provider', 'status', 'created_at']
        )


class ChannelZoneViewSet(viewsets.ModelViewSet):
    """ViewSet for ChannelZone model.
    
    Manages regional zones for channels with specific
    configurations for different geographical areas.
    """
    
    queryset = ChannelZone.objects.all()
    serializer_class = ChannelZoneSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = ChannelZoneFilter
    search_fields = ['zone_name', 'region_name', 'description']
    ordering_fields = ['zone_name', 'region_name', 'created_at']
    ordering = ['channel__name', 'zone_name']
    
    def perform_create(self, serializer):
        """Set creator when creating a zone."""
        serializer.save(created_by=self.request.user)
    
    def perform_update(self, serializer):
        """Set updater when updating a zone."""
        serializer.save(updated_by=self.request.user)
    
    @action(detail=False, methods=['get'])
    def by_channel(self, request):
        """Get zones grouped by channel."""
        channel_id = request.query_params.get('channel_id')
        if channel_id:
            zones = self.queryset.filter(channel_id=channel_id, status='active')
        else:
            zones = self.queryset.filter(status='active')
        
        serializer = self.get_serializer(zones, many=True)
        return Response(serializer.data)


class ChannelCodecViewSet(viewsets.ModelViewSet):
    """ViewSet for ChannelCodec model.
    
    Manages codec configurations for different quality levels
    and technical specifications for each channel.
    """
    
    queryset = ChannelCodec.objects.all()
    serializer_class = ChannelCodecSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = ChannelCodecFilter
    search_fields = ['quality_level', 'video_codec', 'audio_codec']
    ordering_fields = ['quality_level', 'bitrate', 'created_at']
    ordering = ['channel__name', 'quality_level']
    
    def perform_create(self, serializer):
        """Set creator when creating a codec configuration."""
        serializer.save(created_by=self.request.user)
    
    def perform_update(self, serializer):
        """Set updater when updating a codec configuration."""
        serializer.save(updated_by=self.request.user)


class JingleViewSet(viewsets.ModelViewSet):
    """ViewSet for Jingle model.
    
    Manages audio jingles used by channels for branding,
    transitions, and promotional content.
    """
    
    queryset = Jingle.objects.all()
    serializer_class = JingleSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = JingleFilter
    search_fields = ['name', 'description', 'audio_format']
    ordering_fields = ['name', 'duration', 'play_order', 'created_at']
    ordering = ['channel__name', 'play_order', 'name']
    parser_classes = [MultiPartParser, FormParser]
    
    def get_serializer_class(self):
        """Return appropriate serializer based on action."""
        if self.action == 'upload':
            return JingleUploadSerializer
        return JingleSerializer
    
    def perform_create(self, serializer):
        """Set creator when creating a jingle."""
        serializer.save(created_by=self.request.user)
    
    def perform_update(self, serializer):
        """Set updater when updating a jingle."""
        serializer.save(updated_by=self.request.user)
    
    @action(detail=False, methods=['post'])
    def upload(self, request):
        """Upload jingle audio file."""
        serializer = JingleUploadSerializer(data=request.data)
        if serializer.is_valid():
            jingle = serializer.save(created_by=request.user)
            return Response(
                JingleSerializer(jingle).data,
                status=status.HTTP_201_CREATED
            )
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=False, methods=['get'])
    def by_type(self, request):
        """Get jingles by type (intro, outro, transition)."""
        jingle_type = request.query_params.get('type')
        channel_id = request.query_params.get('channel_id')
        
        queryset = self.queryset.filter(status='active')
        
        if channel_id:
            queryset = queryset.filter(channel_id=channel_id)
        
        if jingle_type == 'intro':
            queryset = queryset.filter(is_intro=True)
        elif jingle_type == 'outro':
            queryset = queryset.filter(is_outro=True)
        elif jingle_type == 'transition':
            queryset = queryset.filter(is_transition=True)
        
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class DayTimeViewSet(viewsets.ModelViewSet):
    """ViewSet for DayTime model.
    
    Manages time slots and programming periods for channels.
    Used for scheduling and time-based content management.
    """
    
    queryset = DayTime.objects.all()
    serializer_class = DayTimeSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_class = DayTimeFilter
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'start_time', 'priority', 'created_at']
    ordering = ['day_of_week', 'start_time']
    
    def perform_create(self, serializer):
        """Set creator when creating a time slot."""
        serializer.save(created_by=self.request.user)
    
    def perform_update(self, serializer):
        """Set updater when updating a time slot."""
        serializer.save(updated_by=self.request.user)
    
    @action(detail=False, methods=['get'])
    def prime_time(self, request):
        """Get prime time slots."""
        slots = self.queryset.filter(is_prime_time=True, status='active')
        serializer = self.get_serializer(slots, many=True)
        return Response(serializer.data)


# ============================================================================
# Traditional Django Views
# ============================================================================

@login_required
def channel_list(request):
    """Display list of channels with filtering and pagination."""
    channels = Channel.objects.all().order_by('name')
    
    # Apply filters
    provider = request.GET.get('provider')
    status_filter = request.GET.get('status')
    search = request.GET.get('search')
    
    if provider:
        channels = channels.filter(provider=provider)
    
    if status_filter:
        channels = channels.filter(status=status_filter)
    
    if search:
        channels = channels.filter(
            Q(name__icontains=search) |
            Q(channel_code__icontains=search) |
            Q(description__icontains=search)
        )
    
    # Pagination
    paginator = Paginator(channels, 25)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'page_obj': page_obj,
        'providers': Channel.PROVIDER_CHOICES,
        'current_provider': provider,
        'current_status': status_filter,
        'current_search': search,
    }
    
    return render(request, 'channels/channel_list.html', context)


@login_required
def channel_detail(request, pk):
    """Display detailed view of a specific channel."""
    channel = get_object_or_404(Channel, pk=pk)
    zones = channel.zones.filter(status='active')
    codecs = channel.codecs.filter(status='active')
    jingles = channel.jingles.filter(status='active')
    
    context = {
        'channel': channel,
        'zones': zones,
        'codecs': codecs,
        'jingles': jingles,
    }
    
    return render(request, 'channels/channel_detail.html', context)


@login_required
def jingle_list(request):
    """Display list of jingles with filtering."""
    jingles = Jingle.objects.select_related('channel').all().order_by('channel__name', 'name')
    
    # Apply filters
    channel_id = request.GET.get('channel')
    jingle_type = request.GET.get('type')
    search = request.GET.get('search')
    
    if channel_id:
        jingles = jingles.filter(channel_id=channel_id)
    
    if jingle_type == 'intro':
        jingles = jingles.filter(is_intro=True)
    elif jingle_type == 'outro':
        jingles = jingles.filter(is_outro=True)
    elif jingle_type == 'transition':
        jingles = jingles.filter(is_transition=True)
    
    if search:
        jingles = jingles.filter(
            Q(name__icontains=search) |
            Q(description__icontains=search)
        )
    
    # Pagination
    paginator = Paginator(jingles, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'page_obj': page_obj,
        'channels': Channel.objects.filter(status='active').order_by('name'),
        'current_channel': channel_id,
        'current_type': jingle_type,
        'current_search': search,
    }
    
    return render(request, 'channels/jingle_list.html', context)


# ============================================================================
# AJAX Views
# ============================================================================

@require_http_methods(["GET"])
def ajax_channel_zones(request, channel_id):
    """AJAX endpoint to get zones for a specific channel."""
    try:
        channel = Channel.objects.get(pk=channel_id)
        zones = channel.zones.filter(status='active').values(
            'id', 'zone_name', 'region_name', 'is_primary'
        )
        return JsonResponse({
            'success': True,
            'zones': list(zones)
        })
    except Channel.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Channel not found'
        }, status=404)
    except Exception as e:
        logger.error(f"Error fetching channel zones: {str(e)}")
        return JsonResponse({
            'success': False,
            'error': 'Internal server error'
        }, status=500)


@require_http_methods(["GET"])
def ajax_channel_jingles(request, channel_id):
    """AJAX endpoint to get jingles for a specific channel."""
    try:
        channel = Channel.objects.get(pk=channel_id)
        jingles = channel.jingles.filter(status='active').values(
            'id', 'name', 'duration', 'is_intro', 'is_outro', 'is_transition'
        )
        return JsonResponse({
            'success': True,
            'jingles': list(jingles)
        })
    except Channel.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Channel not found'
        }, status=404)
    except Exception as e:
        logger.error(f"Error fetching channel jingles: {str(e)}")
        return JsonResponse({
            'success': False,
            'error': 'Internal server error'
        }, status=500)


@csrf_exempt
@require_http_methods(["POST"])
def ajax_toggle_channel_status(request, channel_id):
    """AJAX endpoint to toggle channel status."""
    try:
        channel = Channel.objects.get(pk=channel_id)
        new_status = 'active' if channel.status == 'inactive' else 'inactive'
        channel.status = new_status
        channel.updated_by = request.user
        channel.save()
        
        return JsonResponse({
            'success': True,
            'new_status': new_status,
            'message': f'Channel {channel.name} {new_status}'
        })
    except Channel.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Channel not found'
        }, status=404)
    except Exception as e:
        logger.error(f"Error toggling channel status: {str(e)}")
        return JsonResponse({
            'success': False,
            'error': 'Internal server error'
        }, status=500)


@require_http_methods(["GET"])
def ajax_channel_stats(request):
    """AJAX endpoint to get channel statistics."""
    try:
        stats = {
            'total_channels': Channel.objects.count(),
            'active_channels': Channel.objects.filter(status='active').count(),
            'providers': list(Channel.objects.values('provider').annotate(
                count=Count('id')
            ).order_by('-count')),
            'recent_channels': list(Channel.objects.filter(
                created_at__gte=timezone.now() - timedelta(days=30)
            ).values('name', 'created_at')),
        }
        return JsonResponse({
            'success': True,
            'stats': stats
        })
    except Exception as e:
        logger.error(f"Error fetching channel stats: {str(e)}")
        return JsonResponse({
            'success': False,
            'error': 'Internal server error'
        }, status=500)