from django.contrib import admin
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.db.models import Count, Q, Max
from django.contrib.admin import SimpleListFilter
from django.forms import ModelForm, ValidationError
from django.utils import timezone
from django.core.validators import MinValueValidator
from datetime import timedelta, time, datetime
import logging

from .models import Playlists, Windows, Avails, AdspotsInAvail, Verifs

logger = logging.getLogger(__name__)


# Custom Filters
class PlaylistStatusFilter(SimpleListFilter):
    title = _('Status')
    parameter_name = 'status'

    def lookups(self, request, model_admin):
        return (
            ('draft', _('Draft')),
            ('published', _('Published')),
            ('active', _('Currently Active')),
        )

    def queryset(self, request, queryset):
        if self.value() == 'draft':
            return queryset.filter(is_draft=True)
        if self.value() == 'published':
            return queryset.filter(is_draft=False)
        if self.value() == 'active':
            now = timezone.now()
            return queryset.filter(
                is_draft=False,
                start_date__lte=now,
                end_date__gte=now
            )
        return queryset


class BroadcastDateFilter(SimpleListFilter):
    title = _('Broadcast Period')
    parameter_name = 'broadcast_period'

    def lookups(self, request, model_admin):
        return (
            ('today', _('Today')),
            ('tomorrow', _('Tomorrow')),
            ('this_week', _('This Week')),
            ('next_week', _('Next Week')),
            ('past', _('Past Broadcasts')),
        )

    def queryset(self, request, queryset):
        today = timezone.now().date()
        
        if self.value() == 'today':
            return queryset.filter(broadcast_date=today)
        if self.value() == 'tomorrow':
            return queryset.filter(broadcast_date=today + timedelta(days=1))
        if self.value() == 'this_week':
            start_week = today - timedelta(days=today.weekday())
            end_week = start_week + timedelta(days=6)
            return queryset.filter(broadcast_date__range=[start_week, end_week])
        if self.value() == 'next_week':
            start_next_week = today + timedelta(days=7-today.weekday())
            end_next_week = start_next_week + timedelta(days=6)
            return queryset.filter(broadcast_date__range=[start_next_week, end_next_week])
        if self.value() == 'past':
            return queryset.filter(broadcast_date__lt=today)
        return queryset


class VerificationStatusFilter(SimpleListFilter):
    title = _('Verification Status')
    parameter_name = 'verification_status'

    def lookups(self, request, model_admin):
        return (
            ('complete', _('Complete')),
            ('pending', _('Pending')),
            ('successful', _('Successful Broadcast')),
            ('failed', _('Failed Broadcast')),
        )

    def queryset(self, request, queryset):
        if self.value() == 'complete':
            return queryset.filter(
                Q(vercomplete__iexact='complete') |
                Q(vercomplete__iexact='yes') |
                Q(vercomplete__iexact='1') |
                Q(vercomplete__iexact='true')
            )
        if self.value() == 'pending':
            return queryset.exclude(
                Q(vercomplete__iexact='complete') |
                Q(vercomplete__iexact='yes') |
                Q(vercomplete__iexact='1') |
                Q(vercomplete__iexact='true')
            )
        if self.value() == 'successful':
            return queryset.filter(
                Q(airStatuscode__iexact='success') |
                Q(airStatuscode__iexact='ok') |
                Q(airStatuscode__iexact='200') |
                Q(airStatuscode__iexact='aired') |
                Q(airStatuscode__iexact='broadcast')
            )
        if self.value() == 'failed':
            return queryset.exclude(
                Q(airStatuscode__iexact='success') |
                Q(airStatuscode__iexact='ok') |
                Q(airStatuscode__iexact='200') |
                Q(airStatuscode__iexact='aired') |
                Q(airStatuscode__iexact='broadcast')
            )
        return queryset


class BroadcastTimeFilter(SimpleListFilter):
    title = _('Broadcast Time')
    parameter_name = 'broadcast_time'

    def lookups(self, request, model_admin):
        return (
            ('morning', _('Morning (06:00-12:00)')),
            ('afternoon', _('Afternoon (12:00-18:00)')),
            ('evening', _('Evening (18:00-24:00)')),
            ('night', _('Night (00:00-06:00)')),
        )

    def queryset(self, request, queryset):
        if self.value() == 'morning':
            return queryset.filter(air_time__range=[time(6, 0), time(11, 59)])
        if self.value() == 'afternoon':
            return queryset.filter(air_time__range=[time(12, 0), time(17, 59)])
        if self.value() == 'evening':
            return queryset.filter(air_time__range=[time(18, 0), time(23, 59)])
        if self.value() == 'night':
            return queryset.filter(air_time__range=[time(0, 0), time(5, 59)])
        return queryset


# Custom Forms
class PlaylistAdminForm(ModelForm):
    class Meta:
        model = Playlists
        fields = '__all__'

    def clean(self):
        cleaned_data = super().clean()
        start_date = cleaned_data.get('start_date')
        end_date = cleaned_data.get('end_date')
        
        if start_date and end_date and start_date >= end_date:
            raise ValidationError({
                'end_date': _("End date must be after start date.")
            })
        
        return cleaned_data


class WindowAdminForm(ModelForm):
    class Meta:
        model = Windows
        fields = '__all__'

    def clean(self):
        cleaned_data = super().clean()
        window_start = cleaned_data.get('window_start')
        window_end = cleaned_data.get('window_end')
        
        if window_start and window_end and window_start >= window_end:
            raise ValidationError({
                'window_end': _("Window end time must be after start time.")
            })
        
        return cleaned_data


class VerificationAdminForm(ModelForm):
    class Meta:
        model = Verifs
        fields = '__all__'

    def clean(self):
        cleaned_data = super().clean()
        traffic_id = cleaned_data.get('trafficId')
        spot_id = cleaned_data.get('spotId')
        
        if traffic_id and not spot_id:
            raise ValidationError({
                'spotId': _("Spot ID is required when Traffic ID is provided.")
            })
        
        return cleaned_data


# Inline Admin Classes
class WindowsInline(admin.TabularInline):
    model = Windows
    form = WindowAdminForm
    extra = 0
    fields = ('window_start', 'window_end', 'window_duration', 'avails_count')
    readonly_fields = ('avails_count',)
    
    def avails_count(self, obj):
        if obj.pk:
            count = obj.get_avails_count()
            if count > 0:
                url = reverse('admin:playlists_avails_changelist')
                return format_html(
                    '<a href="{}?window__id__exact={}">{} avails</a>',
                    url, obj.pk, count
                )
            return '0 avails'
        return '-'
    avails_count.short_description = _('Avails')


class AvailsInline(admin.TabularInline):
    model = Avails
    extra = 0
    fields = ('avail_start', 'availinwindow', 'adspots_count')
    readonly_fields = ('adspots_count',)
    
    def adspots_count(self, obj):
        if obj.pk:
            count = obj.get_adspots_count()
            if count > 0:
                url = reverse('admin:playlists_adspotsinAvail_changelist')
                return format_html(
                    '<a href="{}?avail__id__exact={}">{} spots</a>',
                    url, obj.pk, count
                )
            return '0 spots'
        return '-'
    adspots_count.short_description = _('Ad Spots')


class AdspotsInAvailInline(admin.TabularInline):
    model = AdspotsInAvail
    extra = 0
    fields = ('adspot', 'positioninavail', 'trafficid')
    autocomplete_fields = ('adspot',)


# Main Admin Classes
@admin.register(Playlists)
class PlaylistsAdmin(admin.ModelAdmin):
    form = PlaylistAdminForm
    list_display = (
        'id', 'version', 'channel', 'broadcast_date', 'status_badge', 
        'duration_display', 'windows_count', 'total_avails', 'created_at'
    )
    list_filter = (
        PlaylistStatusFilter, BroadcastDateFilter, 'channel', 'zone_channel',
        'created_at', 'updated_at'
    )
    search_fields = ('version', 'channel__channel_name', 'zone_channel__region', 'xml_file')
    date_hierarchy = 'broadcast_date'
    ordering = ('-created_at', '-broadcast_date')
    
    fieldsets = (
        (_('Basic Information'), {
            'fields': ('channel', 'zone_channel', 'version')
        }),
        (_('Broadcast Schedule'), {
            'fields': ('broadcast_date', 'start_date', 'end_date')
        }),
        (_('Status & Versioning'), {
            'fields': ('is_draft', 'draft_version', 'xml_file')
        }),
        (_('Metadata'), {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )
    readonly_fields = ('created_at', 'updated_at')
    
    inlines = [WindowsInline]
    
    actions = ['publish_playlists', 'create_copies', 'mark_as_draft']
    
    # Custom display methods
    def channel_name(self, obj):
        return obj.channel.channel_name if obj.channel else _('No Channel')
    channel_name.short_description = _('Channel')
    channel_name.admin_order_field = 'channel__name'
    
    def status_badge(self, obj):
        if obj.is_draft:
            color = 'orange'
            text = _('Draft')
        else:
            color = 'green'
            text = _('Published')
        
        return format_html(
            '<span style="color: {}; font-weight: bold;">{}</span>',
            color, text
        )
    status_badge.short_description = _('Status')
    status_badge.admin_order_field = 'is_draft'
    
    def duration_display(self, obj):
        hours = obj.duration_hours
        if hours:
            return f"{hours}h"
        return '-'
    duration_display.short_description = _('Duration')
    
    def windows_count(self, obj):
        count = obj.get_windows_count()
        if count > 0:
            url = reverse('admin:playlists_windows_changelist')
            return format_html(
                '<a href="{}?playlist__id__exact={}">{}</a>',
                url, obj.pk, count
            )
        return '0'
    windows_count.short_description = _('Windows')
    
    def total_avails(self, obj):
        count = obj.get_total_avails_count()
        if count > 0:
            return format_html('<strong>{}</strong>', count)
        return '0'
    total_avails.short_description = _('Total Avails')
    
    # Custom actions
    def publish_playlists(self, request, queryset):
        updated = 0
        for playlist in queryset.filter(is_draft=True):
            if playlist.publish(user=request.user):
                updated += 1
        
        self.message_user(
            request,
            _('Successfully published {} playlists.').format(updated)
        )
    publish_playlists.short_description = _('Publish selected playlists')
    
    def create_copies(self, request, queryset):
        copies_created = 0
        for playlist in queryset:
            new_version = f"{playlist.version}_copy_{timezone.now().strftime('%Y%m%d_%H%M')}"
            playlist.create_copy(new_version=new_version)
            copies_created += 1
        
        self.message_user(
            request,
            _('Successfully created {} playlist copies.').format(copies_created)
        )
    create_copies.short_description = _('Create copies of selected playlists')
    
    def mark_as_draft(self, request, queryset):
        updated = queryset.update(is_draft=True)
        self.message_user(
            request,
            _('Successfully marked {} playlists as draft.').format(updated)
        )
    mark_as_draft.short_description = _('Mark selected playlists as draft')


@admin.register(Windows)
class WindowsAdmin(admin.ModelAdmin):
    form = WindowAdminForm
    list_display = (
        'id', 'playlist_info', 'window_start', 'window_end', 
        'duration_display', 'avails_count', 'total_adspots'
    )
    list_filter = ('playlist__channel', 'playlist__is_draft', 'window_start')
    search_fields = (
        'playlist__version', 'playlist__channel__channel_name'
    )
    ordering = ('playlist__broadcast_date', 'window_start')
    
    fieldsets = (
        (_('Playlist Association'), {
            'fields': ('playlist',)
        }),
        (_('Window Timing'), {
            'fields': ('window_start', 'window_end', 'window_duration')
        }),
        (_('Metadata'), {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )
    readonly_fields = ('created_at', 'updated_at')
    
    inlines = [AvailsInline]
    
    # Custom display methods
    def playlist_info(self, obj):
        if obj.playlist:
            url = reverse('admin:playlists_playlists_change', args=[obj.playlist.pk])
            status = _('Draft') if obj.playlist.is_draft else _('Published')
            return format_html(
                '<a href="{}">{}</a> <small>({})</small>',
                url, obj.playlist.version, status
            )
        return _('No Playlist')
    playlist_info.short_description = _('Playlist')
    playlist_info.admin_order_field = 'playlist__version'
    
    def duration_display(self, obj):
        if obj.window_duration:
            total_seconds = obj.window_duration.total_seconds()
            minutes = int(total_seconds // 60)
            seconds = int(total_seconds % 60)
            return f"{minutes}m {seconds}s"
        return '-'
    duration_display.short_description = _('Duration')
    
    def avails_count(self, obj):
        count = obj.get_avails_count()
        if count > 0:
            url = reverse('admin:playlists_avails_changelist')
            return format_html(
                '<a href="{}?window__id__exact={}">{}</a>',
                url, obj.pk, count
            )
        return '0'
    avails_count.short_description = _('Avails')
    
    def total_adspots(self, obj):
        count = obj.get_total_adspots_count()
        return count if count > 0 else '0'
    total_adspots.short_description = _('Ad Spots')


@admin.register(Avails)
class AvailsAdmin(admin.ModelAdmin):
    list_display = (
        'id', 'window_info', 'avail_start', 'availinwindow', 
        'adspots_count', 'availability_status'
    )
    list_filter = (
        'window__playlist__channel', 'window__playlist__is_draft', 
        'avail_start'
    )
    search_fields = (
        'window__playlist__version', 'availinwindow',
        'window__playlist__channel__channel_name'
    )
    ordering = ('window__playlist__broadcast_date', 'window__window_start', 'avail_start')
    
    fieldsets = (
        (_('Window Association'), {
            'fields': ('window',)
        }),
        (_('Avail Details'), {
            'fields': ('avail_start', 'availinwindow')
        }),
        (_('Metadata'), {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )
    readonly_fields = ('created_at', 'updated_at')
    
    inlines = [AdspotsInAvailInline]
    
    # Custom display methods
    def window_info(self, obj):
        if obj.window:
            url = reverse('admin:playlists_windows_change', args=[obj.window.pk])
            return format_html(
                '<a href="{}">Window {}</a> <small>({} - {})</small>',
                url, obj.window.pk, 
                obj.window.window_start or '-',
                obj.window.window_end or '-'
            )
        return _('No Window')
    window_info.short_description = _('Window')
    window_info.admin_order_field = 'window__id'
    
    def adspots_count(self, obj):
        count = obj.get_adspots_count()
        if count > 0:
            # url = reverse('admin:playlists_adspotsinAvail_changelist')
            url = ""
            return format_html(
                '<a href="{}?avail__id__exact={}">{}</a>',
                url, obj.pk, count
            )
        return '0'
    adspots_count.short_description = _('Ad Spots')
    
    def availability_status(self, obj):
        if obj.is_available():
            return format_html(
                '<span style="color: green;">✓ {}</span>',
                _('Available')
            )
        else:
            return format_html(
                '<span style="color: red;">✗ {}</span>',
                _('Occupied')
            )
    availability_status.short_description = _('Status')


@admin.register(AdspotsInAvail)
class AdspotsInAvailAdmin(admin.ModelAdmin):
    list_display = (
        'id', 'avail_info', 'adspot_info', 'positioninavail', 
        'trafficid', 'created_at'
    )
    list_filter = (
        'avail__window__playlist__channel',
        'avail__window__playlist__is_draft',
        'positioninavail',
    )
    search_fields = (
        'avail__window__playlist__version',
        'adspot__name',
        'trafficid',
    )
    ordering = ('avail__window__playlist__broadcast_date', 'avail__avail_start', 'positioninavail')
    
    fieldsets = (
        (_('Placement Details'), {
            'fields': ('avail', 'adspot', 'positioninavail')
        }),
        (_('Traffic Integration'), {
            'fields': ('trafficid',)
        }),
        (_('Metadata'), {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )
    readonly_fields = ('created_at', 'updated_at')
    
    autocomplete_fields = ('adspot',)
    
    # Custom display methods
    def avail_info(self, obj):
        if obj.avail:
            url = reverse('admin:playlists_avails_change', args=[obj.avail.pk])
            return format_html(
                '<a href="{}">Avail {}</a> <small>({})</small>',
                url, obj.avail.pk, obj.avail.avail_start or '-'
            )
        return _('No Avail')
    avail_info.short_description = _('Avail')
    avail_info.admin_order_field = 'avail__id'
    
    def adspot_info(self, obj):
        if obj.adspot:
            try:
                url = reverse('admin:campaigns_adspots_change', args=[obj.adspot.pk])
                return format_html(
                    '<a href="{}">{}</a>',
                    url, str(obj.adspot)
                )
            except:
                return str(obj.adspot)
        return _('No Ad Spot')
    adspot_info.short_description = _('Ad Spot')
    adspot_info.admin_order_field = 'adspot__id'


@admin.register(Verifs)
class VerifsAdmin(admin.ModelAdmin):
    form = VerificationAdminForm
    list_display = (
        'spotId', 'networkname', 'zonename', 'broadcast_date', 
        'air_time', 'duration_display', 'status_badge', 
        'verification_badge', 'revision', 'created_at'
    )
    list_filter = (
        VerificationStatusFilter, BroadcastTimeFilter, 'networkname', 
        'zonename', 'airStatuscode', 'revision', 'broadcast_date'
    )
    search_fields = (
        'spotId', 'trafficId', 'networkname', 'zonename', 'airStatuscode'
    )
    date_hierarchy = 'broadcast_date'
    ordering = ('-broadcast_date', '-air_time', '-revision')
    
    fieldsets = (
        (_('Identification'), {
            'fields': ('spotId', 'trafficId')
        }),
        (_('Network Information'), {
            'fields': ('networkname', 'zonename')
        }),
        (_('Broadcast Details'), {
            'fields': ('broadcast_date', 'air_time', 'air_length')
        }),
        (_('Status & Verification'), {
            'fields': ('airStatuscode', 'vercomplete', 'revision')
        }),
        (_('Metadata'), {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )
    readonly_fields = ('created_at', 'updated_at')
    
    actions = ['mark_complete', 'create_revisions', 'export_broadcast_summary']
    
    # Custom display methods
    def duration_display(self, obj):
        if obj.air_length:
            total_seconds = obj.air_length.total_seconds()
            minutes = int(total_seconds // 60)
            seconds = int(total_seconds % 60)
            return f"{minutes}:{seconds:02d}"
        return '-'
    duration_display.short_description = _('Duration')
    duration_display.admin_order_field = 'air_length'
    
    def status_badge(self, obj):
        if obj.is_successful_broadcast:
            color = 'green'
            text = _('Success')
        else:
            color = 'red'
            text = obj.airStatuscode or _('Unknown')
        
        return format_html(
            '<span style="color: {}; font-weight: bold;">{}</span>',
            color, text
        )
    status_badge.short_description = _('Broadcast Status')
    status_badge.admin_order_field = 'airStatuscode'
    
    def verification_badge(self, obj):
        if obj.is_verification_complete:
            color = 'green'
            icon = '✓'
            text = _('Complete')
        else:
            color = 'orange'
            icon = '○'
            text = _('Pending')
        
        return format_html(
            '<span style="color: {}; font-weight: bold;">{} {}</span>',
            color, icon, text
        )
    verification_badge.short_description = _('Verification')
    verification_badge.admin_order_field = 'vercomplete'
    
    # Custom actions
    def mark_complete(self, request, queryset):
        updated = 0
        for verification in queryset:
            if not verification.is_verification_complete:
                verification.mark_complete(user=request.user)
                updated += 1
        
        self.message_user(
            request,
            _('Successfully marked {} verifications as complete.').format(updated)
        )
    mark_complete.short_description = _('Mark selected verifications as complete')
    
    def create_revisions(self, request, queryset):
        revisions_created = 0
        for verification in queryset:
            verification.create_revision()
            revisions_created += 1
        
        self.message_user(
            request,
            _('Successfully created {} new revisions.').format(revisions_created)
        )
    create_revisions.short_description = _('Create new revisions for selected verifications')
    
    def export_broadcast_summary(self, request, queryset):
        """Custom action to export broadcast summary"""
        from django.http import JsonResponse
        
        summaries = []
        for verification in queryset:
            summaries.append(verification.get_broadcast_summary())
        
        response = JsonResponse({'verifications': summaries}, json_dumps_params={'indent': 2})
        response['Content-Disposition'] = 'attachment; filename="broadcast_summary.json"'
        return response
    export_broadcast_summary.short_description = _('Export broadcast summary')
    
    def changelist_view(self, request, extra_context=None):
        """Add summary statistics to changelist view"""
        extra_context = extra_context or {}
        
        # Get summary statistics
        queryset = self.get_queryset(request)
        total_verifications = queryset.count()
        
        # Count complete verifications and successful broadcasts
        complete_verifications = 0
        successful_broadcasts = 0
        
        for verification in queryset:
            if verification.is_verification_complete:
                complete_verifications += 1
            if verification.is_successful_broadcast:
                successful_broadcasts += 1
        
        extra_context['summary_stats'] = {
            'total': total_verifications,
            'complete': complete_verifications,
            'successful': successful_broadcasts,
            'completion_rate': (complete_verifications / total_verifications * 100) if total_verifications > 0 else 0,
            'success_rate': (successful_broadcasts / total_verifications * 100) if total_verifications > 0 else 0,
        }
        
        return super().changelist_view(request, extra_context=extra_context)


# Custom Admin Site Configuration
class BroadcastAdminSite(admin.AdminSite):
    site_header = _('Broadcast Management System')
    site_title = _('Broadcast Admin')
    index_title = _('Broadcast Administration')
    
    def get_app_list(self, request, app_label=None):
        """
        Return a sorted list of all the installed apps that have been
        registered in this site.
        """
        app_list = super().get_app_list(request, app_label)
        
        # Custom ordering for broadcast models
        broadcast_order = ['Playlists', 'Windows', 'Avails', 'AdspotsInAvail', 'Verifs']
        
        for app in app_list:
            if app['app_label'] == 'playlists':  # Replace with your app name
                app['models'].sort(key=lambda x: broadcast_order.index(x['object_name']) 
                                 if x['object_name'] in broadcast_order else 999)
        
        return app_list


# Optional: Register with custom admin site
# broadcast_admin_site = BroadcastAdminSite(name='broadcast_admin')
# broadcast_admin_site.register(Playlists, PlaylistsAdmin)
# broadcast_admin_site.register(Windows, WindowsAdmin)
# broadcast_admin_site.register(Avails, AvailsAdmin)
# broadcast_admin_site.register(AdspotsInAvail, AdspotsInAvailAdmin)
# broadcast_admin_site.register(Verifs, VerifsAdmin)