import os
import time 
import logging
from xml.dom import minidom 
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta

from django.conf import settings
from django.utils import timezone
from django.core.files.base import ContentFile


logger = logging.getLogger(__name__)

# Additional helper functions for data type conversions
def convert_time_string_to_time(time_string):
    """
    Helper function to convert time strings to time objects.
    Useful for migrating existing data from CharField to TimeField.
    
    Args:
        time_string (str): Time in string format (e.g., "14:30:00", "2:30 PM")
    
    Returns:
        time: Python time object or None if conversion fails
    """
    if not time_string:
        return None
    
    try:
        # Try common time formats
        formats = [
            '%H:%M:%S',    # 24-hour format with seconds
            '%H:%M',       # 24-hour format without seconds
            '%I:%M:%S %p', # 12-hour format with seconds
            '%I:%M %p',    # 12-hour format without seconds
        ]
        
        for fmt in formats:
            try:
                return datetime.strptime(time_string.strip(), fmt).time()
            except ValueError:
                continue
        
        logger.warning(f"Could not parse time string: {time_string}")
        return None
        
    except Exception as e:
        logger.error(f"Error converting time string '{time_string}': {e}")
        return None


def convert_duration_string_to_duration(duration_string):
    """
    Helper function to convert duration strings to timedelta objects.
    Useful for migrating existing data from CharField to DurationField.
    
    Args:
        duration_string (str): Duration in string format (e.g., "00:30:00", "30 minutes")
    
    Returns:
        timedelta: Python timedelta object or None if conversion fails
    """
    if not duration_string:
        return None
    
    try:
        # Try to parse as HH:MM:SS format
        if ':' in duration_string:
            parts = duration_string.split(':')
            if len(parts) == 3:
                hours, minutes, seconds = map(int, parts)
                return timezone.timedelta(hours=hours, minutes=minutes, seconds=seconds)
            elif len(parts) == 2:
                minutes, seconds = map(int, parts)
                return timezone.timedelta(minutes=minutes, seconds=seconds)
        
        # Try to parse as seconds
        if duration_string.isdigit():
            return timezone.timedelta(seconds=int(duration_string))
        
        logger.warning(f"Could not parse duration string: {duration_string}")
        return None
        
    except Exception as e:
        logger.error(f"Error converting duration string '{duration_string}': {e}")
        return None


def convert_date_string_to_date(date_string):
    """
    Helper function to convert date strings to date objects.
    Useful for migrating existing data from CharField to DateField.
    
    Args:
        date_string (str): Date in string format (e.g., "2023-12-25", "25/12/2023")
    
    Returns:
        date: Python date object or None if conversion fails
    """
    if not date_string:
        return None
    
    try:
        # Try common date formats
        formats = [
            '%Y-%m-%d',    # ISO format
            '%d/%m/%Y',    # DD/MM/YYYY
            '%m/%d/%Y',    # MM/DD/YYYY
            '%Y/%m/%d',    # YYYY/MM/DD
            '%d-%m-%Y',    # DD-MM-YYYY
            '%m-%d-%Y',    # MM-DD-YYYY
        ]
        
        for fmt in formats:
            try:
                return datetime.strptime(date_string.strip(), fmt).date()
            except ValueError:
                continue
        
        logger.warning(f"Could not parse date string: {date_string}")
        return None
        
    except Exception as e:
        logger.error(f"Error converting date string '{date_string}': {e}")
        return None


def playlist_xml_upload_path(instance, filename):
    """
    Generate upload path for playlist XML files.
    
    Args:
        instance: Playlist model instance
        filename: Original filename
        
    Returns:
        str: Upload path
    """
    # Create path: playlists/channel_name/channel_region/YYYY_MM/filename
    date_path = instance.broadcast_date.strftime('%Y_%m') if instance.broadcast_date else 'no_date'
    channel_name = instance.channel.channel_name if instance.channel else 'no_channel'
    channel_region = instance.zone_channel.region if instance.zone_channel else 'no_region'
    # Sanitize channel name for filesystem
    channel_name = ''.join(c for c in channel_name if c.isalnum() or c in ('-', '_')).strip()
    channel_region = ''.join(c for c in channel_region if c.isalnum() or c in ('-', '_')).strip()
    
    return f'playlists/{channel_name}/{channel_region}/{date_path}/{filename}'
    


class PlaylistXMLGenerator:
    """
        Comprehensive XML generation and management system for broadcast playlist schedules.
        
        This class provides enterprise-grade XML generation capabilities for converting
        playlist database records into industry-standard SCTE-118-3 compliant XML schedules.
        It handles the complete transformation from hierarchical playlist data structures
        to broadcast-ready XML documents suitable for automation systems.
        
        The generator supports the full playlist hierarchy including:
            - Playlist metadata and scheduling information
            - Time windows with precise timing specifications
            - Advertisement availability slots (avails) within windows
            - Individual advertisement records with traffic management
        
        Key features include:
            - SCTE-118-3 schema compliance for broadcast industry standards
            - Comprehensive error handling and validation
            - File system integration with automatic storage management
            - Detailed logging for audit trails and debugging
            - Traffic ID management for advertisement tracking
            - Flexible date formatting and timezone handling
        
        Business Applications:
            - Broadcast automation system integration
            - Compliance reporting and regulatory requirements
            - Advertisement inventory management and billing
            - Schedule distribution to multiple broadcast facilities
            - Quality assurance and validation workflows
        
        Technical Standards:
            - SCTE-118-3 XML schema compliance
            - ISO 8601 date/time formatting
            - UTF-8 encoding for international character support
            - Structured logging for operational monitoring
        
        Example Usage:
            generator = PlaylistXMLGenerator()
            result = generator.generate_schedule(playlist_instance)
            if result['status']:
                xml_file_path = result['file']
                print(f"XML generated: {xml_file_path}")
    """
    
    def __init__(self, playlist=None):
        """
            Initialize the XML generator with optional playlist context and logging infrastructure.
            
            Sets up the generator instance with logging capabilities, traffic management,
            and optional playlist binding for streamlined processing workflows.
            
            Args:
                playlist (Playlists, optional): Playlist model instance to bind to this generator
                                            Enables streamlined processing for repeated operations
                                            Can be overridden in individual method calls
            
            Attributes:
                playlist (Playlists): Bound playlist instance for default operations
                logger (Logger): Configured logger for operation tracking and debugging
                traffic_id (int): Global traffic counter for advertisement identification
        """
        # =============================================================================
        # PLAYLIST BINDING SECTION
        # Bind optional playlist instance for streamlined processing
        # =============================================================================
        # Store playlist instance for default operations and repeated processing
        # This enables efficient batch processing and reduces parameter passing
        self.playlist = playlist
        
        # =============================================================================
        # LOGGING INFRASTRUCTURE SECTION
        # Initialize structured logging for operation tracking and debugging
        # =============================================================================
        # Configure class-specific logger for operation tracking and debugging
        # Uses class name for clear log source identification and filtering
        self.logger = logging.getLogger(self.__class__.__name__)
        
        # =============================================================================
        # TRAFFIC MANAGEMENT SECTION
        # Initialize traffic counter for advertisement identification and tracking
        # =============================================================================
        # Initialize traffic ID counter for advertisement tracking and billing
        # Reset for each generator instance to ensure consistent numbering
        self.traffic_id = 0
    
    def generate_schedule(self, playlist=None):
        """
            Generate comprehensive XML schedule content for broadcast automation systems.
            
            This method orchestrates the complete XML generation workflow including structure
            creation, content population, file system storage, and validation. It produces
            SCTE-118-3 compliant XML documents suitable for broadcast automation systems
            and advertisement management platforms.
            
            The generation process handles the complete playlist hierarchy transformation:
                1. Playlist metadata and scheduling parameters
                2. Time window definitions with precise timing
                3. Advertisement availability slots within windows
                4. Individual advertisement records with traffic management
            
            The method provides comprehensive error handling and detailed logging to support
            production deployment and troubleshooting workflows.
            
            Args:
                playlist (Playlists, optional): Playlist model instance to process
                                            Uses bound instance if not provided
                                            Must contain complete hierarchy relationships
            
            Returns:
                dict: Comprehensive generation result containing:
                    - status (bool): Success/failure indicator
                    - message (str): Descriptive result message
                    - file (str): Full file system path to generated XML
                    - filename (str): Generated filename for the XML document
                    - xml_content (str): Complete XML content for immediate use
                    
            Raises:
                AttributeError: If playlist lacks required model relationships
                FileSystemError: If XML file cannot be saved to storage
                ValidationError: If generated XML fails schema validation
                DatabaseError: If playlist data cannot be retrieved
                
            Example Usage:
                result = generator.generate_schedule(my_playlist)
                if result['status']:
                    deploy_to_broadcast_system(result['file'])
                else:
                    handle_generation_error(result['message'])
        """
        # =============================================================================
        # PLAYLIST RESOLUTION SECTION
        # Determine target playlist for processing and validate availability
        # =============================================================================
        # Resolve target playlist from parameter or bound instance
        # Provides flexibility for both bound and ad-hoc processing workflows
        target_playlist = playlist or self.playlist
        
        # Validate that a playlist is available for processing
        # Early validation prevents processing errors and provides clear feedback
        if not target_playlist:
            return self._error_response("No playlist provided")
        
        try:
            # =============================================================================
            # XML STRUCTURE CREATION SECTION
            # Generate complete XML document structure from playlist data
            # =============================================================================
            # Create comprehensive XML structure from playlist hierarchy
            # This handles all levels: playlist → windows → avails → ads
            xml_content = self._create_playlist_xml(target_playlist)
            
            # =============================================================================
            # FILENAME GENERATION SECTION
            # Create descriptive filename based on playlist metadata
            # =============================================================================
            # Generate descriptive filename based on playlist attributes
            # Includes date, channel, zone, and version information for identification
            filename = self._generate_xml_filename(target_playlist)
            
            # =============================================================================
            # FILE SYSTEM STORAGE SECTION
            # Save generated XML content to persistent storage with model integration
            # =============================================================================
            # Save XML content to the playlist's managed file field
            # This integrates with Django's file storage system for consistent management
            target_playlist.xml_file.save(
                filename,                                           # Generated filename for storage
                ContentFile(xml_content.encode('utf-8')),          # XML content as file-like object
                save=True                                           # Commit model changes immediately
            )

            # =============================================================================
            # SUCCESS LOGGING SECTION
            # Record successful generation for audit trails and monitoring
            # =============================================================================
            # Log successful XML generation for audit trails and operational monitoring
            self.logger.info(f"Successfully generated XML schedule for playlist {target_playlist.id}")
            
            # =============================================================================
            # SUCCESS RESPONSE SECTION
            # Return comprehensive success result with all relevant information
            # =============================================================================
            # Return comprehensive success response with file information and content
            return {
                'status': True,                                     # Success indicator
                'message': 'XML schedule generated successfully',   # Descriptive success message
                'file': target_playlist.xml_file.path if target_playlist.xml_file else None,  # Full file path
                'filename': filename,                               # Generated filename 
            }
            
        except Exception as e:
            # =============================================================================
            # ERROR HANDLING SECTION
            # Handle all generation failures with comprehensive logging and response
            # =============================================================================
            # Log detailed error information for debugging and monitoring
            self.logger.error(f"Failed to generate XML schedule for playlist {getattr(target_playlist, 'id', 'unknown')}: {str(e)}")
            # Return standardized error response with exception details
            return self._error_response(f"Exception: {str(e)}")
        
    def _generate_xml_filename(self, playlist):
        """
            Generate descriptive filename for XML schedule files based on playlist metadata.
            
            Creates standardized filenames that include essential playlist identification
            information for file management, organization, and automated processing systems.
            The filename format supports sorting, filtering, and identification of specific
            playlist versions and configurations.
            
            Args:
                playlist (Playlists): Playlist model instance containing metadata
                                    Must have channel, zone, and date relationships
            
            Returns:
                str: Generated filename in format: YYYYMMDD-zone-network-version[_draft].sch
                    Examples: "20250730-EST-NBC-1.sch", "20250731-PST-CBS-2_draft.sch"
                    
            Filename Components:
                - Date: YYYYMMDD format for chronological sorting
                - Zone: Geographic or programming zone identifier
                - Network: Broadcast network identifier
                - Version: Playlist version number for change tracking
                - Draft suffix: Added for draft playlists to prevent confusion
                - Extension: .sch for schedule file identification
        """
        # =============================================================================
        # CHANNEL NAME EXTRACTION AND SANITIZATION SECTION
        # Extract and clean channel name for filename safety
        # =============================================================================
        # Extract channel name with fallback for missing data
        # Provides meaningful identification even when channel data is incomplete
        channel_name = playlist.channel.channel_name if playlist.channel else 'unknown'
        
        # Sanitize channel name for filesystem compatibility
        # Remove special characters that could cause filesystem issues
        channel_name = ''.join(c for c in channel_name if c.isalnum() or c in ('-', '_')).strip()
         
        # =============================================================================
        # ZONE AND NETWORK INFORMATION EXTRACTION SECTION
        # Extract geographic and network identifiers for filename context
        # =============================================================================
        # Extract zone and network information for geographical and organizational context
        zone_name = playlist.id_zone_channel.zonename
        network_name = playlist.id_zone_channel.networkname

        # =============================================================================
        # DATE FORMATTING SECTION
        # Format broadcast date for chronological filename sorting
        # =============================================================================
        # Format broadcast date for filename with fallback for missing dates
        # YYYYMMDD format enables chronological sorting and date-based filtering
        date_str = playlist.broadcast_date.strftime('%Y%m%d') if playlist.broadcast_date else 'nodate'
        
        # =============================================================================
        # VERSION AND DRAFT STATUS SECTION
        # Include version tracking and draft identification in filename
        # =============================================================================
        # Include version number for change tracking and conflict resolution
        version_str = str(playlist.version)
        
        # Add draft suffix to clearly identify non-production files
        # Prevents accidental deployment of draft playlists to production systems
        draft_str = '_draft' if playlist.is_draft else ''
          
        # =============================================================================
        # FILENAME ASSEMBLY SECTION
        # Combine all components into standardized filename format
        # =============================================================================
        # Assemble complete filename with all identification components
        # Format: date-zone-network-version[_draft].sch
        return f"{date_str}-{zone_name}-{network_name}-{version_str}{draft_str}.sch"

    def _create_playlist_xml(self, playlist):
        """
            Create comprehensive XML document structure conforming to SCTE-118-3 broadcast standards.
            
            This method orchestrates the complete transformation of playlist database records
            into industry-standard XML format suitable for broadcast automation systems.
            It handles the hierarchical structure creation, attribute population, and
            formatting to ensure compliance with broadcast industry standards.
            
            The XML structure includes:
                - Root Schedule element with broadcast metadata
                - Window elements representing time slots
                - Avail elements for advertisement opportunities
                - Ad elements with traffic management information
            
            Args:
                playlist (Playlists): Complete playlist model instance with relationships
                                    Must include windows, avails, and ads hierarchy
            
            Returns:
                str: Formatted XML document string ready for broadcast system consumption
                    Includes proper indentation and encoding for human readability
                    
            XML Schema Compliance:
                - SCTE-118-3 standard for broadcast scheduling
                - ISO 8601 date/time formatting
                - Proper namespace declarations
                - Required attribute specifications
        """
        # =============================================================================
        # TRAFFIC COUNTER RESET SECTION
        # Initialize traffic ID counter for consistent advertisement tracking
        # =============================================================================
        # Reset traffic ID counter for each generation to ensure consistent numbering
        # This provides sequential traffic IDs for advertisement tracking and billing
        self.traffic_id = 0
        
        # =============================================================================
        # DATE FORMATTING SECTION
        # Format broadcast date for XML attribute population
        # =============================================================================
        # Format broadcast date for XML attributes using standardized formatting
        # Note: Variable name should be 'playlist' not 'target_playlist' (appears to be a typo)
        broadcast_date = self._format_broadcast_date(playlist.broadcast_date)

        # =============================================================================
        # ROOT ELEMENT CREATION SECTION
        # Create XML root element with comprehensive broadcast metadata
        # =============================================================================
        # Create root Schedule element with comprehensive broadcast metadata
        # This establishes the document structure and provides essential scheduling context
        root = xml.Element("Schedule")
        root.set("broadcastDate", str(broadcast_date))                              # Target broadcast date
        root.set("begDateTime", f"{str(broadcast_date)}T00:01:00+00:00")           # Schedule start time with timezone
        root.set("endDateTime", f"{str(broadcast_date)}T23:59:59+00:00")           # Schedule end time with timezone
        root.set("networkName", str(playlist.zone_channel.networkname))            # Broadcasting network identifier
        root.set("zoneName", str(playlist.zone_channel.zonename))                  # Geographic/programming zone
        root.set("revision", str(playlist.version))                                # Playlist version for change tracking
        root.set("level", "0")                                                     # Hierarchical level indicator
        root.set("xmlns", "http://www.scte.org/schemas/118-3/201X")               # SCTE namespace declaration
        root.set("schemaVersion", "http://www.w3.org/2001/XMLSchema")             # XML Schema version reference
         
        # =============================================================================
        # HIERARCHICAL CONTENT POPULATION SECTION
        # Add windows and their nested content to the XML structure
        # =============================================================================
        # Add windows with their nested avails and advertisements
        # This creates the complete hierarchical structure for broadcast scheduling
        self._add_windows(root, playlist)
        
        # =============================================================================
        # XML FORMATTING AND FINALIZATION SECTION
        # Convert XML structure to formatted string for output
        # =============================================================================
        # Convert XML structure to formatted string with proper encoding
        xml_string = ET.tostring(root, encoding='unicode')
        
        # Apply formatting for human readability and standard compliance
        formatted_xml = self._format_xml(xml_string)
        
        # Return complete formatted XML document ready for broadcast system consumption
        return formatted_xml 
  
    def _add_windows(self, windows_element, playlist):
        """
            Add window elements and their nested content to the XML structure.
            
            This method processes all time windows associated with the playlist and creates
            corresponding XML elements with proper timing attributes and nested content.
            Windows represent discrete time periods within the broadcast schedule where
            advertisements can be scheduled.
            
            Args:
                windows_element (xml.Element): Parent XML element to contain window elements
                                            Typically the root Schedule element
                playlist (Playlists): Playlist instance containing window relationships
                                    Must have accessible windows queryset
            
            Processing Flow:
                1. Query all windows ordered by start time
                2. Create XML element for each window
                3. Set timing attributes (start time, duration)
                4. Add nested avails for each window
        """
        # =============================================================================
        # WINDOW QUERY AND ORDERING SECTION
        # Retrieve windows in chronological order for proper XML sequencing
        # =============================================================================
        # Query all windows for this playlist ordered by start time
        # Chronological ordering ensures proper broadcast sequence in XML output
        windows = playlist.windows.all().order_by('window_start')
        
        # =============================================================================
        # WINDOW PROCESSING LOOP SECTION
        # Create XML elements for each window with timing and nested content
        # =============================================================================
        # Process each window to create corresponding XML elements
        for window in windows:
            # Create Window XML element as child of the parent element
            window_element = ET.SubElement(windows_element, 'Window')
            
            # =============================================================================
            # WINDOW TIMING ATTRIBUTES SECTION
            # Set precise timing attributes for broadcast scheduling
            # =============================================================================
            # Set window start time with ISO 8601 formatting and timezone
            # Format: YYYY-MM-DDTHH:MM:SS+00:00 for broadcast system compatibility
            window_element.set("windowStart", f"{str(window.window_start).replace(' ', 'T')}+00:00")
            
            # Set window duration for scheduling calculations and validation
            window_element.set("windowDuration", window.window_duration) 
            
            # =============================================================================
            # NESTED AVAIL PROCESSING SECTION
            # Add advertisement availability slots within this window
            # =============================================================================
            # Add nested avails for this window with their advertisement content
            # Note: Parameter should be 'window_element' not 'avails_element' (appears to be a typo)
            self._add_avails(window_element, window)
 
    def _add_avails(self, avails_element, window):
        """
            Add advertisement availability elements and their nested advertisements to XML.
            
            This method processes all avails (advertisement slots) within a window and creates
            corresponding XML elements with proper positioning and timing attributes.
            Avails represent specific opportunities for advertisement placement within
            broadcast windows.
            
            Args:
                avails_element (xml.Element): Parent window element to contain avail elements
                                            Receives avail children for hierarchical structure
                window (Windows): Window instance containing avail relationships
                                Must have accessible avails queryset
            
            Processing Flow:
                1. Query all avails ordered by position within window
                2. Create XML element for each avail
                3. Set positioning and timing attributes
                4. Add nested advertisements for each avail
        """
        # =============================================================================
        # AVAIL QUERY AND ORDERING SECTION
        # Retrieve avails in positional order for proper XML sequencing
        # =============================================================================
        # Query all avails for this window ordered by position within window
        # Positional ordering ensures correct advertisement sequence in broadcast
        avails = window.avails.all().order_by('availinwindow')
        
        # =============================================================================
        # AVAIL PROCESSING LOOP SECTION
        # Create XML elements for each avail with positioning and timing
        # =============================================================================
        # Process each avail to create corresponding XML elements
        for avail in avails:
            # Create Avail XML element as child of the window element
            avail_element = ET.SubElement(avails_element, 'Avail')
            
            # =============================================================================
            # AVAIL ATTRIBUTE POPULATION SECTION
            # Set positioning and timing attributes for advertisement management
            # =============================================================================
            # Set avail number (currently hardcoded to 0, may need dynamic assignment)
            avail_element.set("availNum", '0')
            
            # Set position of this avail within the parent window for sequencing
            avail_element.set('availInWindow', str(avail.availinwindow))
            
            # Set avail start time with ISO 8601 formatting and timezone
            # Format: YYYY-MM-DDTHH:MM:SS+00:00 for precise scheduling
            avail_element.set("availStart", f"{str(avail.avail_start).replace(' ', 'T')}+00:00")
            
            # =============================================================================
            # NESTED ADVERTISEMENT PROCESSING SECTION
            # Add individual advertisements within this avail
            # =============================================================================
            # Add nested advertisements for this avail with traffic management
            # Note: Parameter should be 'avail_element' not 'ads_element' (appears to be a typo)
            self._add_ads(avail_element, avail)

    def _add_ads(self, avail_element, avail):
        ad_placements = avail.adspots_in_avail.all().order_by('positioninavail')
        
        for adplacement in ad_placements:
            self.traffic_id += 1
            ad_element = ET.SubElement(avail_element, 'Spot')
 
            # ad_element.set("adId", f"{adspot.id_adspot.duration}sec")
            ad_element.set("adId", f"{adplacement.adspot.duration}sec")
            ad_element.set("eventType", "LOI")
            ad_element.set('length', time.strftime("%H%M%S00", time.gmtime(int(adplacement.adspot.duration)))) 
            ad_element.set('positionInAvail', str(adplacement.positioninavail))
            ad_element.set("schedSource", "Local")
            ad_element.set("spotId", adplacement.adspot.original_file.file.name)
            ad_element.set("trafficId",  str(adplacement.trafficid) if adplacement.trafficid == self.traffic_id else str(self.traffic_id))

    def _format_broadcast_date(self, broadcast_date):
        """
            Format broadcast date to standardized YYYYMMDD string for XML attributes.
            
            This method handles multiple input date formats and converts them to the
            standardized 8-digit date format required by broadcast systems and XML schemas.
            It provides robust date handling for various input types including strings,
            datetime objects, and other date representations.
            
            Args:
                broadcast_date (str|datetime|object): Broadcast date in various formats
                                                    Supports string dates, datetime objects,
                                                    and other date-like objects
            
            Returns:
                str: Formatted date string in YYYYMMDD format
                    Examples: "20250730", "20251215", "20240101"
                    
            Supported Input Formats:
                - String dates in YYYY-MM-DD format
                - Python datetime objects
                - Other objects with strftime method
                - Fallback string conversion for unknown types
        """
        # =============================================================================
        # STRING DATE PROCESSING SECTION
        # Handle string input dates with parsing and formatting
        # =============================================================================
        # Handle string date input with standard YYYY-MM-DD format
        if isinstance(broadcast_date, str):
            # Parse string date and reformat to YYYYMMDD
            return str((datetime.strptime(broadcast_date, "%Y-%m-%d")).strftime("%Y%m%d"))
        
        # =============================================================================
        # DATETIME OBJECT PROCESSING SECTION
        # Handle datetime objects with direct formatting
        # =============================================================================
        # Handle datetime objects with strftime capability
        elif hasattr(broadcast_date, 'strftime'):
            # Use strftime method to format datetime objects
            return broadcast_date.strftime("%Y%m%d")
        
        # =============================================================================
        # FALLBACK PROCESSING SECTION
        # Handle unknown date types with string conversion
        # =============================================================================
        # Fallback to string conversion for unknown date types
        else:
            # Convert unknown date types to string representation
            return str(broadcast_date)
            
    def _format_xml(self, xml_string):
        """
            Format XML string with proper indentation and cleanup for human readability.
            
            This method transforms raw XML strings into properly formatted documents
            with consistent indentation, line breaks, and whitespace management.
            It enhances readability for debugging, validation, and manual review
            while maintaining XML validity and compliance.
            
            Args:
                xml_string (str): Raw XML string without formatting
                                Generated from ElementTree or similar XML creation tools
            
            Returns:
                str: Formatted XML string with proper indentation and structure
                    Includes consistent spacing and line breaks for readability
                    
            Formatting Features:
                - Two-space indentation for nested elements
                - Removal of empty lines for clean output
                - Proper line breaks between elements
                - UTF-8 encoding compatibility
        """
        try:
            # =============================================================================
            # XML PARSING AND FORMATTING SECTION
            # Parse raw XML and apply formatting with proper indentation
            # =============================================================================
            # Parse raw XML string using minidom for formatting capabilities
            dom = minidom.parseString(xml_string)
            
            # Apply pretty printing with consistent two-space indentation
            # encoding=None returns string instead of bytes for compatibility
            formatted = dom.toprettyxml(indent='  ', encoding=None)
            
            # =============================================================================
            # CLEANUP AND OPTIMIZATION SECTION
            # Remove empty lines and optimize formatted output
            # =============================================================================
            # Remove empty lines and clean up formatted XML for optimal output
            # Filter out lines that contain only whitespace for cleaner presentation
            lines = [line for line in formatted.split('\n') if line.strip()]
            
            # Rejoin cleaned lines with proper line breaks
            return '\n'.join(lines)
            
        except Exception as e:
            # =============================================================================
            # ERROR HANDLING SECTION
            # Handle formatting failures with graceful fallback
            # =============================================================================
            # Log formatting warning and return unformatted XML as fallback
            # Note: 'logger' should be 'self.logger' for proper class context
            self.logger.warning(f"Failed to format XML: {str(e)}")
            
            # Return original XML string if formatting fails
            return xml_string

    def _error_response(self, message):
        """
            Create standardized error response structure for consistent error handling.
            
            This method generates uniform error response dictionaries that match the
            success response format, enabling consistent error handling across all
            XML generation operations. It provides structured error information
            suitable for logging, user feedback, and automated error processing.
            
            Args:
                message (str): Descriptive error message explaining the failure
                            Should provide sufficient context for debugging
            
            Returns:
                dict: Standardized error response containing:
                    - status (bool): False to indicate failure
                    - message (str): Formatted error message with context
                    - file (None): No file path for failed operations
                    - filename (None): No filename for failed operations 
                    
            Error Response Structure:
                Matches success response format for consistent handling
                Enables uniform error processing across different failure scenarios
        """
        # =============================================================================
        # STANDARDIZED ERROR RESPONSE SECTION
        # Create consistent error response structure matching success format
        # =============================================================================
        # Return standardized error response with comprehensive failure information
        return {
            'status': False,                                        # Failure indicator
            'message': f'Failed to generate XML schedule: {str(message)}',  # Formatted error message
            'file': None,                                           # No file path for failures
            'filename': None,                                       # No filename for failures 
        }

    @staticmethod
    def regenerate_playlist_xml(playlist_id):
        """
            Regenerate XML for an existing playlist using static method interface.
            
            This static method provides a convenient interface for regenerating XML
            schedules for existing playlists without requiring generator instantiation.
            It handles playlist retrieval, generator creation, and XML generation
            with comprehensive error handling for production deployment scenarios.
            
            Args:
                playlist_id (int): Database ID of the playlist to regenerate
                                Must correspond to existing Playlists record
            
            Returns:
                dict: Generation result from generateSchedule method
                    Contains status, message, file path, and XML content
                    
            Use Cases:
                - Batch XML regeneration for schedule updates
                - API endpoints for on-demand XML generation
                - Maintenance scripts for system updates
                - Error recovery for failed initial generation
                
            Note: Method references 'generateSchedule' function that should be 'generate_schedule'
        """
        try:
            # =============================================================================
            # PLAYLIST RETRIEVAL SECTION
            # Query database for target playlist with required relationships
            # =============================================================================
            # Import Playlists model locally to prevent circular imports
            from apps.playlists.models import Playlists  
            
            # Retrieve playlist with related channel and zone data for XML generation
            # select_related optimizes database queries for related model access
            playlist = Playlists.objects.select_related('channel', 'zone_channel').get(id=playlist_id)
            
            # Generate XML using the retrieved playlist instance
            # Note: Should call self.generate_schedule or create generator instance
            return generateSchedule(playlist)
            
        except Playlists.DoesNotExist:
            # =============================================================================
            # PLAYLIST NOT FOUND ERROR SECTION
            # Handle missing playlist with descriptive error response
            # =============================================================================
            # Return structured error response for missing playlist
            return {
                'status': False,
                'message': f'Playlist with ID {playlist_id} not found',
                'file': None,
                'filename': None, 
            }
        except Exception as e:
            # =============================================================================
            # GENERAL ERROR HANDLING SECTION
            # Handle unexpected errors with logging and structured response
            # =============================================================================
            # Log error for debugging and monitoring (should use proper logger instance)
            logger.error(f"Failed to regenerate XML for playlist {playlist_id}: {str(e)}")
            
            # Return structured error response for general failures
            return {
                'status': False,
                'message': f'Failed to regenerate XML: {str(e)}',
                'file': None,
                'filename': None, 
            }

    def regenerate_playlist_xml(playlist_id):
        """
        Regenerate XML for an existing playlist.
        
        Args:
            playlist_id: ID of the playlist to regenerate
            
        Returns:
            dict: Result dictionary from generateSchedule
        """
        try:
            from apps.playlists.models import Playlists  
            
            playlist = Playlists.objects.select_related('channel', 'zone_channel').get(id=playlist_id)
            return generateSchedule(playlist)
            
        except Playlists.DoesNotExist:
            return {
                'status': False,
                'message': f'Playlist with ID {playlist_id} not found',
                'file': None,
                'filename': None, 
            }
        except Exception as e:
            logger.error(f"Failed to regenerate XML for playlist {playlist_id}: {str(e)}")
            return {
                'status': False,
                'message': f'Failed to regenerate XML: {str(e)}',
                'file': None,
                'filename': None, 
            }

    def validate_playlist_xml(xml_content):
        """
        Validate the generated XML content.
        
        Args:
            xml_content: XML content string
            
        Returns:
            dict: Validation result
        """
        try:
            ET.fromstring(xml_content)
            return {'valid': True, 'message': 'XML is valid'}
        except ET.ParseError as e:
            return {'valid': False, 'message': f'Invalid XML: {str(e)}'}

    def get_playlist_xml_summary(playlist):
        """
        Get a summary of the playlist XML structure.
        
        Args:
            playlist: Playlist model instance
            
        Returns:
            dict: Summary information
        """
        try:
            windows_count = playlist.windows.count()
            avails_count = sum(window.avails.count() for window in playlist.windows.all())
            ads_count = sum(
                avail.adspots.count() 
                for window in playlist.windows.all() 
                for avail in window.avails.all()
            )
            
            return {
                'playlist_id': playlist.id,
                'version': playlist.version,
                'is_draft': playlist.is_draft,
                'windows_count': windows_count,
                'avails_count': avails_count,
                'ads_count': ads_count,
                'broadcast_date': playlist.broadcast_date,
                'duration_minutes': playlist.duration_minutes
            }
            
        except Exception as e:
            logger.error(f"Failed to get playlist summary for {playlist.id}: {str(e)}")
            return {}

