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
from django.core.paginator import Paginator
from django.db.models import Q, Count, Avg
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.db import transaction
from datetime import timedelta

from apps.channels.models import Channel, ChannelZone, ChannelCodec, EPGProgram, Jingle, ChannelSchedule
from apps.core.models import ActivityLog


@login_required
def channel_list(request):
    """List all channels with filtering and pagination."""
    channels = Channel.objects.select_related('zone', 'codec').all()
    
    # Filtering
    search = request.GET.get('search')
    if search:
        channels = channels.filter(
            Q(name__icontains=search) |
            Q(display_name__icontains=search) |
            Q(description__icontains=search)
        )
    
    channel_type = request.GET.get('type')
    if channel_type:
        channels = channels.filter(channel_type=channel_type)
    
    status = request.GET.get('status')
    if status:
        channels = channels.filter(status=status)
    
    zone_id = request.GET.get('zone')
    if zone_id:
        channels = channels.filter(zone_id=zone_id)
    
    # Annotate with program counts
    channels = channels.annotate(
        program_count=Count('programs'),
        jingle_count=Count('jingles')
    )
    
    # Pagination
    paginator = Paginator(channels, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Get filter options
    zones = ChannelZone.objects.filter(is_active=True).order_by('name')
    
    context = {
        'page_obj': page_obj,
        'zones': zones,
        'channel_types': Channel.CHANNEL_TYPES,
        'status_choices': Channel.STATUS_CHOICES,
        'current_search': search,
        'current_type': channel_type,
        'current_status': status,
        'current_zone': zone_id,
    }
    
    return render(request, 'channels/channel_list.html', context)


@login_required
def channel_detail(request, channel_id):
    """Channel detail view with EPG and performance metrics."""
    channel = get_object_or_404(
        Channel.objects.select_related('zone', 'codec'),
        id=channel_id
    )
    
    # Get current and upcoming programs
    now = timezone.now()
    current_program = channel.programs.filter(
        start_time__lte=now,
        end_time__gte=now
    ).first()
    
    upcoming_programs = channel.programs.filter(
        start_time__gt=now
    ).order_by('start_time')[:5]
    
    # Get recent programs
    recent_programs = channel.programs.filter(
        end_time__lt=now
    ).order_by('-end_time')[:5]
    
    # Get jingles
    jingles = channel.jingles.filter(is_active=True).order_by('-priority', 'name')
    
    # Get schedules
    schedules = channel.schedules.filter(
        start_time__gte=now - timedelta(hours=2),
        start_time__lte=now + timedelta(hours=24)
    ).order_by('start_time')
    
    # Recent activity
    recent_activity = ActivityLog.objects.filter(
        content_type__model='channel',
        object_id=channel.id
    ).select_related('user').order_by('-created_at')[:10]
    
    context = {
        'channel': channel,
        'current_program': current_program,
        'upcoming_programs': upcoming_programs,
        'recent_programs': recent_programs,
        'jingles': jingles,
        'schedules': schedules,
        'recent_activity': recent_activity,
    }
    
    return render(request, 'channels/channel_detail.html', context)


@login_required
def channel_create(request):
    """Create a new channel."""
    if not request.user.profile.can_manage_campaigns():
        messages.error(request, 'You do not have permission to create channels.')
        return redirect('channels:list')
    
    if request.method == 'POST':
        try:
            with transaction.atomic():
                channel = Channel.objects.create(
                    name=request.POST['name'],
                    display_name=request.POST.get('display_name', ''),
                    channel_number=request.POST.get('channel_number') or None,
                    channel_type=request.POST.get('channel_type', 'tv'),
                    status=request.POST.get('status', 'active'),
                    stream_url=request.POST.get('stream_url', ''),
                    backup_stream_url=request.POST.get('backup_stream_url', ''),
                    codec_id=request.POST.get('codec') or None,
                    zone_id=request.POST.get('zone') or None,
                    description=request.POST.get('description', ''),
                    website=request.POST.get('website', ''),
                    language=request.POST.get('language', ''),
                    category=request.POST.get('category', ''),
                    target_audience=request.POST.get('target_audience', ''),
                    supports_dai=request.POST.get('supports_dai') == 'on',
                    max_ad_duration=int(request.POST.get('max_ad_duration', 180)),
                    min_ad_gap=int(request.POST.get('min_ad_gap', 300)),
                )
                
                # Handle logo upload
                if 'logo' in request.FILES:
                    channel.logo = request.FILES['logo']
                    channel.save()
                
                # Log activity
                ActivityLog.objects.create(
                    user=request.user,
                    action='CREATE',
                    content_type='Channel',
                    object_id=channel.id,
                    description=f'Created channel: {channel.name}'
                )
                
                messages.success(request, f'Channel "{channel.name}" created successfully.')
                return redirect('channels:detail', channel_id=channel.id)
                
        except Exception as e:
            messages.error(request, f'Error creating channel: {str(e)}')
    
    # Get form data
    zones = ChannelZone.objects.filter(is_active=True).order_by('name')
    codecs = ChannelCodec.objects.all().order_by('name')
    
    context = {
        'zones': zones,
        'codecs': codecs,
        'channel_types': Channel.CHANNEL_TYPES,
        'status_choices': Channel.STATUS_CHOICES,
    }
    
    return render(request, 'channels/channel_form.html', context)


@login_required
def channel_edit(request, channel_id):
    """Edit an existing channel."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    if not request.user.profile.can_manage_campaigns():
        messages.error(request, 'You do not have permission to edit channels.')
        return redirect('channels:detail', channel_id=channel.id)
    
    if request.method == 'POST':
        try:
            with transaction.atomic():
                channel.name = request.POST['name']
                channel.display_name = request.POST.get('display_name', '')
                channel.channel_number = request.POST.get('channel_number') or None
                channel.channel_type = request.POST.get('channel_type', 'tv')
                channel.status = request.POST.get('status', 'active')
                channel.stream_url = request.POST.get('stream_url', '')
                channel.backup_stream_url = request.POST.get('backup_stream_url', '')
                channel.codec_id = request.POST.get('codec') or None
                channel.zone_id = request.POST.get('zone') or None
                channel.description = request.POST.get('description', '')
                channel.website = request.POST.get('website', '')
                channel.language = request.POST.get('language', '')
                channel.category = request.POST.get('category', '')
                channel.target_audience = request.POST.get('target_audience', '')
                channel.supports_dai = request.POST.get('supports_dai') == 'on'
                channel.max_ad_duration = int(request.POST.get('max_ad_duration', 180))
                channel.min_ad_gap = int(request.POST.get('min_ad_gap', 300))
                
                # Handle logo upload
                if 'logo' in request.FILES:
                    channel.logo = request.FILES['logo']
                
                channel.save()
                
                # Log activity
                ActivityLog.objects.create(
                    user=request.user,
                    action='UPDATE',
                    content_type='Channel',
                    object_id=channel.id,
                    description=f'Updated channel: {channel.name}'
                )
                
                messages.success(request, f'Channel "{channel.name}" updated successfully.')
                return redirect('channels:detail', channel_id=channel.id)
                
        except Exception as e:
            messages.error(request, f'Error updating channel: {str(e)}')
    
    # Get form data
    zones = ChannelZone.objects.filter(is_active=True).order_by('name')
    codecs = ChannelCodec.objects.all().order_by('name')
    
    context = {
        'channel': channel,
        'zones': zones,
        'codecs': codecs,
        'channel_types': Channel.CHANNEL_TYPES,
        'status_choices': Channel.STATUS_CHOICES,
        'is_edit': True,
    }
    
    return render(request, 'channels/channel_form.html', context)


@login_required
def epg_list(request, channel_id):
    """List EPG programs for a channel."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    programs = channel.programs.all()
    
    # Filtering
    date_filter = request.GET.get('date')
    if date_filter:
        try:
            filter_date = timezone.datetime.strptime(date_filter, '%Y-%m-%d').date()
            programs = programs.filter(
                start_time__date=filter_date
            )
        except ValueError:
            pass
    
    program_type = request.GET.get('type')
    if program_type:
        programs = programs.filter(program_type=program_type)
    
    # Pagination
    paginator = Paginator(programs.order_by('start_time'), 50)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'channel': channel,
        'page_obj': page_obj,
        'program_types': EPGProgram.PROGRAM_TYPES,
        'current_date': date_filter,
        'current_type': program_type,
    }
    
    return render(request, 'channels/epg_list.html', context)


@login_required
def jingle_list(request, channel_id):
    """List jingles for a channel."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    jingles = channel.jingles.all()
    
    # Filtering
    jingle_type = request.GET.get('type')
    if jingle_type:
        jingles = jingles.filter(jingle_type=jingle_type)
    
    is_active = request.GET.get('active')
    if is_active == 'true':
        jingles = jingles.filter(is_active=True)
    elif is_active == 'false':
        jingles = jingles.filter(is_active=False)
    
    # Pagination
    paginator = Paginator(jingles.order_by('-priority', 'name'), 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'channel': channel,
        'page_obj': page_obj,
        'jingle_types': Jingle.JINGLE_TYPES,
        'current_type': jingle_type,
        'current_active': is_active,
    }
    
    return render(request, 'channels/jingle_list.html', context)


@login_required
def jingle_upload(request, channel_id):
    """Upload a new jingle for a channel."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    if request.method == 'POST':
        try:
            jingle = Jingle.objects.create(
                channel=channel,
                name=request.POST['name'],
                jingle_type=request.POST['jingle_type'],
                file=request.FILES['file'],
                duration=int(request.POST['duration']),
                priority=int(request.POST.get('priority', 1)),
                start_date=request.POST.get('start_date') or None,
                end_date=request.POST.get('end_date') or None,
            )
            
            # Log activity
            ActivityLog.objects.create(
                user=request.user,
                action='CREATE',
                content_type='Jingle',
                object_id=jingle.id,
                description=f'Uploaded jingle: {jingle.name} for {channel.name}'
            )
            
            messages.success(request, f'Jingle "{jingle.name}" uploaded successfully.')
            return redirect('channels:jingle_list', channel_id=channel.id)
            
        except Exception as e:
            messages.error(request, f'Error uploading jingle: {str(e)}')
    
    context = {
        'channel': channel,
        'jingle_types': Jingle.JINGLE_TYPES,
    }
    
    return render(request, 'channels/jingle_upload.html', context)


@login_required
@require_http_methods(["POST"])
def channel_health_check(request, channel_id):
    """Perform health check on a channel."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    try:
        # Here you would implement actual health check logic
        # For now, we'll simulate it
        import requests
        import time
        
        start_time = time.time()
        
        if channel.stream_url:
            try:
                response = requests.head(channel.stream_url, timeout=10)
                is_online = response.status_code == 200
            except:
                is_online = False
        else:
            is_online = True  # Assume online if no URL to check
        
        response_time = int((time.time() - start_time) * 1000)  # ms
        
        channel.update_health_status(is_online)
        
        # Log activity
        ActivityLog.objects.create(
            user=request.user,
            action='HEALTH_CHECK',
            content_type='Channel',
            object_id=channel.id,
            description=f'Health check for {channel.name}: {"Online" if is_online else "Offline"}'
        )
        
        return JsonResponse({
            'success': True,
            'is_online': is_online,
            'response_time': response_time,
            'last_check': channel.last_health_check.isoformat() if channel.last_health_check else None
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e)
        })


@login_required
def channel_stats_api(request, channel_id):
    """API endpoint for channel statistics."""
    channel = get_object_or_404(Channel, id=channel_id)
    
    # Get date range
    days = int(request.GET.get('days', 7))
    end_date = timezone.now().date()
    start_date = end_date - timedelta(days=days)
    
    # Get program statistics
    programs = channel.programs.filter(
        start_time__date__gte=start_date,
        start_time__date__lte=end_date
    )
    
    # Daily program counts
    daily_stats = []
    current_date = start_date
    
    while current_date <= end_date:
        day_programs = programs.filter(start_time__date=current_date)
        
        daily_stats.append({
            'date': current_date.isoformat(),
            'program_count': day_programs.count(),
            'total_duration': sum(p.duration for p in day_programs),
        })
        
        current_date += timedelta(days=1)
    
    # Program type breakdown
    program_types = {}
    for program_type, label in EPGProgram.PROGRAM_TYPES:
        count = programs.filter(program_type=program_type).count()
        if count > 0:
            program_types[program_type] = {
                'label': label,
                'count': count
            }
    
    return JsonResponse({
        'daily_stats': daily_stats,
        'program_types': program_types,
        'total_programs': programs.count(),
        'total_jingles': channel.jingles.filter(is_active=True).count(),
        'is_online': channel.is_online,
        'last_health_check': channel.last_health_check.isoformat() if channel.last_health_check else None,
    })