import os
import time
import logging
import traceback

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class UniversalRWLRunner:
    """
    A universal runner for read, write, and list operations with enhanced robustness.
    """

    def __init__(self, max_retries=3, stall_check_attempts=3, encoding='utf-8'):
        """
        Initializes the runner.

        Args:
            max_retries (int): Maximum number of retries for each operation.
            stall_check_attempts (int): Number of attempts to check for stall before escalation.
            encoding (str): Encoding to use for file operations (default: utf-8).
        """
        self.max_retries = max_retries
        self.stall_check_attempts = stall_check_attempts
        self.encoding = encoding
        self.retry_delay = 2  # Delay in seconds between retries

    def read_file(self, filepath):
        """
        Reads the contents of a file with retry logic.

        Args:
            filepath (str): The path to the file.

        Returns:
            str: The contents of the file, or None if the read fails after multiple retries.
        """
        for attempt in range(self.max_retries):
            try:
                with open(filepath, 'r', encoding=self.encoding) as f:
                    return f.read()
            except FileNotFoundError:
                logging.error(f"File not found: {filepath}")
                return None  # Or raise the exception if you prefer
            except Exception as e:
                logging.error(f"Error reading file (attempt {attempt + 1}/{self.max_retries}): {e}")
                if attempt < self.max_retries - 1:
                    time.sleep(self.retry_delay)
                else:
                    logging.error(f"Failed to read file after {self.max_retries} attempts. Giving up.")
                    return None

    def write_file(self, filepath, content):
        """
        Writes content to a file with retry logic and anti-stall check.

        Args:
            filepath (str): The path to the file.
            content (str): The content to write.

        Returns:
            bool: True if the write was successful, False otherwise.
        """
        for attempt in range(self.max_retries):
            try:
                with open(filepath, 'w', encoding=self.encoding) as f:
                    f.write(content)
                
                # Anti-Stall Check
                if self._check_file_creation(filepath, self.stall_check_attempts):
                    logging.info(f"File successfully written to: {filepath}")
                    return True
                else:
                    logging.warning(f"File write appears stalled. Escalating/Skipping: {filepath}")
                    # Implement escalation logic here (e.g., send alert, skip operation)
                    # For now, just log a warning
                    logging.warning(f"Escalation/Skipping logic triggered for: {filepath}")
                    return False  # Consider making this configurable

            except Exception as e:
                logging.error(f"Error writing to file (attempt {attempt + 1}/{self.max_retries}): {e}")
                logging.error(traceback.format_exc())  # Log the full traceback
                if attempt < self.max_retries - 1:
                    time.sleep(self.retry_delay)
                else:
                    logging.error(f"Failed to write to file after {self.max_retries} attempts. Giving up.")
                    return False

    def _check_file_creation(self, filepath, attempts):
         """
         Checks if the file was actually created and has content, with multiple attempts.

         Args:
             filepath (str): The path to the file.
             attempts (int): The number of attempts to check.

         Returns:
             bool: True if the file exists and has content after several attempts, False otherwise.
         """
         for attempt in range(attempts):
             if os.path.exists(filepath) and os.path.getsize(filepath) > 0:
                 return True
             else:
                 time.sleep(1)  # Wait a short time before checking again
         return False


    def list_files(self, directory):
        """
        Lists files in a directory with retry logic.

        Args:
            directory (str): The path to the directory.

        Returns:
            list: A list of filenames in the directory, or None if the listing fails.
        """
        for attempt in range(self.max_retries):
            try:
                return os.listdir(directory)
            except FileNotFoundError:
                logging.error(f"Directory not found: {directory}")
                return None  # Or raise the exception if you prefer
            except Exception as e:
                logging.error(f"Error listing files (attempt {attempt + 1}/{self.max_retries}): {e}")
                if attempt < self.max_retries - 1:
                    time.sleep(self.retry_delay)
                else:
                    logging.error(f"Failed to list files after {self.max_retries} attempts. Giving up.")
                    return None

# Example Usage (Illustrative)
if __name__ == '__main__':
    runner = UniversalRWLRunner()

    # Write example
    filepath = "example.txt"
    content = "This is a test.  We are ensuring UTF-8 encoding."
    if runner.write_file(filepath, content):
        print(f"Successfully wrote to {filepath}")
    else:
        print(f"Failed to write to {filepath}")

    # Read example
    content = runner.read_file(filepath)
    if content:
        print(f"Content of {filepath}: {content}")
    else:
        print(f"Failed to read {filepath}")

    # List example
    files = runner.list_files(".")
    if files:
        print(f"Files in current directory: {files}")
    else:
        print("Failed to list files.")

    # Test anti-stall by writing to a network drive (if available) that might be slow.
    # Or create a dummy slow writer (simulating slow operation).
    # Add checks for slow network drive write here if needed for testing.