# -*- coding: utf-8 -*-
"""
Management command for cleaning up old channel data and performing maintenance.
"""

from django.core.management.base import BaseCommand
from django.db.models import Count, Q
from django.utils import timezone
from datetime import timedelta
from django.core.cache import cache

from ...models import (
    Channel, ChannelZone, ChannelCodec, ChannelZoneRelation,
    EPGProgram, Jingle, JingleDetection, ChannelSchedule
)


class Command(BaseCommand):
    """
    Management command to clean up old channel data and perform maintenance.
    """
    help = 'Clean up old channel data and perform maintenance tasks'
    
    def add_arguments(self, parser):
        parser.add_argument(
            '--epg-days',
            type=int,
            default=30,
            help='Remove EPG programs older than specified days (default: 30)'
        )
        parser.add_argument(
            '--detections-days',
            type=int,
            default=90,
            help='Remove jingle detections older than specified days (default: 90)'
        )
        parser.add_argument(
            '--schedules-days',
            type=int,
            default=365,
            help='Remove old schedules older than specified days (default: 365)'
        )
        parser.add_argument(
            '--inactive-channels-days',
            type=int,
            default=180,
            help='Remove inactive channels older than specified days (default: 180)'
        )
        parser.add_argument(
            '--unused-codecs',
            action='store_true',
            help='Remove unused codecs that are not assigned to any channel'
        )
        parser.add_argument(
            '--unused-zones',
            action='store_true',
            help='Remove unused zones that have no channels'
        )
        parser.add_argument(
            '--orphaned-relations',
            action='store_true',
            help='Remove orphaned channel-zone relations'
        )
        parser.add_argument(
            '--clear-cache',
            action='store_true',
            help='Clear all channel-related cache entries'
        )
        parser.add_argument(
            '--optimize-db',
            action='store_true',
            help='Perform database optimization tasks'
        )
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Show what would be cleaned up without actually doing it'
        )
        parser.add_argument(
            '--verbose',
            action='store_true',
            help='Show detailed information about cleanup operations'
        )
    
    def handle(self, *args, **options):
        epg_days = options['epg_days']
        detections_days = options['detections_days']
        schedules_days = options['schedules_days']
        inactive_channels_days = options['inactive_channels_days']
        unused_codecs = options['unused_codecs']
        unused_zones = options['unused_zones']
        orphaned_relations = options['orphaned_relations']
        clear_cache = options['clear_cache']
        optimize_db = options['optimize_db']
        dry_run = options['dry_run']
        verbose = options['verbose']
        
        self.stdout.write(
            self.style.SUCCESS('Starting channel data cleanup...')
        )
        
        if dry_run:
            self.stdout.write(
                self.style.WARNING('DRY RUN MODE - No changes will be made')
            )
        
        total_cleaned = 0
        
        # Clean up old EPG programs
        if epg_days > 0:
            cleaned = self.cleanup_old_epg_programs(epg_days, dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up old jingle detections
        if detections_days > 0:
            cleaned = self.cleanup_old_jingle_detections(detections_days, dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up old schedules
        if schedules_days > 0:
            cleaned = self.cleanup_old_schedules(schedules_days, dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up inactive channels
        if inactive_channels_days > 0:
            cleaned = self.cleanup_inactive_channels(inactive_channels_days, dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up unused codecs
        if unused_codecs:
            cleaned = self.cleanup_unused_codecs(dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up unused zones
        if unused_zones:
            cleaned = self.cleanup_unused_zones(dry_run, verbose)
            total_cleaned += cleaned
        
        # Clean up orphaned relations
        if orphaned_relations:
            cleaned = self.cleanup_orphaned_relations(dry_run, verbose)
            total_cleaned += cleaned
        
        # Clear cache
        if clear_cache:
            self.clear_channel_cache(dry_run, verbose)
        
        # Optimize database
        if optimize_db:
            self.optimize_database(dry_run, verbose)
        
        # Print summary
        self.stdout.write('\n' + '='*50)
        self.stdout.write(self.style.SUCCESS('CLEANUP SUMMARY'))
        self.stdout.write('='*50)
        
        if dry_run:
            self.stdout.write(
                self.style.WARNING(f'Would clean up {total_cleaned} records')
            )
        else:
            self.stdout.write(
                self.style.SUCCESS(f'Cleaned up {total_cleaned} records')
            )
        
        self.stdout.write('='*50)
    
    def cleanup_old_epg_programs(self, days, dry_run, verbose):
        """
        Clean up old EPG programs.
        """
        cutoff_date = timezone.now() - timedelta(days=days)
        old_programs = EPGProgram.objects.filter(end_time__lt=cutoff_date)
        count = old_programs.count()
        
        if verbose or dry_run:
            self.stdout.write(
                f'EPG Programs older than {days} days: {count}'
            )
        
        if count > 0 and not dry_run:
            old_programs.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} old EPG programs')
            )
        
        return count
    
    def cleanup_old_jingle_detections(self, days, dry_run, verbose):
        """
        Clean up old jingle detections.
        """
        cutoff_date = timezone.now() - timedelta(days=days)
        old_detections = JingleDetection.objects.filter(detected_at__lt=cutoff_date)
        count = old_detections.count()
        
        if verbose or dry_run:
            self.stdout.write(
                f'Jingle detections older than {days} days: {count}'
            )
        
        if count > 0 and not dry_run:
            old_detections.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} old jingle detections')
            )
        
        return count
    
    def cleanup_old_schedules(self, days, dry_run, verbose):
        """
        Clean up old schedules.
        """
        cutoff_date = timezone.now() - timedelta(days=days)
        old_schedules = ChannelSchedule.objects.filter(
            end_time__lt=cutoff_date,
            is_active=False
        )
        count = old_schedules.count()
        
        if verbose or dry_run:
            self.stdout.write(
                f'Old inactive schedules older than {days} days: {count}'
            )
        
        if count > 0 and not dry_run:
            old_schedules.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} old schedules')
            )
        
        return count
    
    def cleanup_inactive_channels(self, days, dry_run, verbose):
        """
        Clean up inactive channels.
        """
        cutoff_date = timezone.now() - timedelta(days=days)
        inactive_channels = Channel.objects.filter(
            status='inactive',
            updated_at__lt=cutoff_date
        )
        count = inactive_channels.count()
        
        if verbose or dry_run:
            self.stdout.write(
                f'Inactive channels older than {days} days: {count}'
            )
            if verbose and count > 0:
                for channel in inactive_channels[:10]:  # Show first 10
                    self.stdout.write(
                        f'  - {channel.name} ({channel.channel_number}) - '
                        f'Last updated: {channel.updated_at}'
                    )
                if count > 10:
                    self.stdout.write(f'  ... and {count - 10} more')
        
        if count > 0 and not dry_run:
            # Delete related data first
            for channel in inactive_channels:
                channel.programs.all().delete()
                channel.jingles.all().delete()
                channel.schedules.all().delete()
            
            inactive_channels.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} inactive channels')
            )
        
        return count
    
    def cleanup_unused_codecs(self, dry_run, verbose):
        """
        Clean up unused codecs.
        """
        unused_codecs = ChannelCodec.objects.annotate(
            channel_count=Count('channels')
        ).filter(channel_count=0, is_active=False)
        
        count = unused_codecs.count()
        
        if verbose or dry_run:
            self.stdout.write(f'Unused codecs: {count}')
            if verbose and count > 0:
                for codec in unused_codecs:
                    self.stdout.write(
                        f'  - {codec.name} ({codec.codec_type})'
                    )
        
        if count > 0 and not dry_run:
            unused_codecs.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} unused codecs')
            )
        
        return count
    
    def cleanup_unused_zones(self, dry_run, verbose):
        """
        Clean up unused zones.
        """
        unused_zones = ChannelZone.objects.annotate(
            channel_count=Count('channels')
        ).filter(channel_count=0, is_active=False)
        
        count = unused_zones.count()
        
        if verbose or dry_run:
            self.stdout.write(f'Unused zones: {count}')
            if verbose and count > 0:
                for zone in unused_zones:
                    self.stdout.write(
                        f'  - {zone.name} ({zone.country})'
                    )
        
        if count > 0 and not dry_run:
            unused_zones.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} unused zones')
            )
        
        return count
    
    def cleanup_orphaned_relations(self, dry_run, verbose):
        """
        Clean up orphaned channel-zone relations.
        """
        # Find relations where channel or zone no longer exists
        orphaned_relations = ChannelZoneRelation.objects.filter(
            Q(channel__isnull=True) | Q(zone__isnull=True)
        )
        
        count = orphaned_relations.count()
        
        if verbose or dry_run:
            self.stdout.write(f'Orphaned channel-zone relations: {count}')
        
        if count > 0 and not dry_run:
            orphaned_relations.delete()
            self.stdout.write(
                self.style.SUCCESS(f'Deleted {count} orphaned relations')
            )
        
        return count
    
    def clear_channel_cache(self, dry_run, verbose):
        """
        Clear channel-related cache entries.
        """
        if verbose or dry_run:
            self.stdout.write('Clearing channel-related cache entries...')
        
        if not dry_run:
            # Clear specific cache patterns
            cache_patterns = [
                'channel_*',
                'zone_*',
                'epg_*',
                'jingle_*',
                'schedule_*'
            ]
            
            # Note: This is a simplified implementation
            # In production, you might want to use more sophisticated cache clearing
            try:
                cache.clear()
                self.stdout.write(
                    self.style.SUCCESS('Cleared all cache entries')
                )
            except Exception as e:
                self.stdout.write(
                    self.style.ERROR(f'Failed to clear cache: {str(e)}')
                )
    
    def optimize_database(self, dry_run, verbose):
        """
        Perform database optimization tasks.
        """
        if verbose or dry_run:
            self.stdout.write('Performing database optimization...')
        
        if not dry_run:
            from django.db import connection
            
            try:
                with connection.cursor() as cursor:
                    # Update statistics (PostgreSQL)
                    if connection.vendor == 'postgresql':
                        cursor.execute('ANALYZE;')
                        self.stdout.write(
                            self.style.SUCCESS('Updated database statistics')
                        )
                    
                    # For other databases, you might want to add specific optimizations
                    elif connection.vendor == 'mysql':
                        # MySQL optimization commands
                        pass
                    elif connection.vendor == 'sqlite':
                        # SQLite optimization commands
                        cursor.execute('VACUUM;')
                        self.stdout.write(
                            self.style.SUCCESS('Vacuumed SQLite database')
                        )
                        
            except Exception as e:
                self.stdout.write(
                    self.style.ERROR(f'Database optimization failed: {str(e)}')
                )
    
    def get_database_stats(self):
        """
        Get database statistics for reporting.
        """
        stats = {
            'channels': Channel.objects.count(),
            'active_channels': Channel.objects.filter(status='active').count(),
            'zones': ChannelZone.objects.count(),
            'codecs': ChannelCodec.objects.count(),
            'epg_programs': EPGProgram.objects.count(),
            'jingles': Jingle.objects.count(),
            'jingle_detections': JingleDetection.objects.count(),
            'schedules': ChannelSchedule.objects.count(),
        }
        
        return stats