"""
Professional logging configuration for WiFi Auto Auth application.
Provides structured, configurable logging with multiple output handlers and log rotation.
"""

import os
import sys
import logging
import logging.handlers
from pathlib import Path
from typing import Optional, Dict, Any
import argparse


class LoggerFactory:
    """Factory class for creating and managing loggers."""

    _loggers: Dict[str, logging.Logger] = {}
    _configured = False
    _default_log_dir = Path("./logs")
    _default_log_file = "wifi_auto_auth.log"

    @classmethod
    def get_logger(cls, name: str) -> logging.Logger:
        """
        Get or create a logger with the specified name.

        Args:
            name: Logger name (typically __name__ of the calling module)

        Returns:
            Configured logger instance
        """
        if not cls._configured:
            cls._setup_logging()

        if name not in cls._loggers:
            logger = logging.getLogger(name)
            cls._loggers[name] = logger

        return cls._loggers[name]

    @classmethod
    def _setup_logging(cls) -> None:
        """Set up the global logging configuration."""
        if cls._configured:
            return

        # Create formatters
        simple_formatter = logging.Formatter(
            fmt='%(asctime)s [%(levelname)-8s] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )

        detailed_formatter = logging.Formatter(
            fmt='%(asctime)s [%(levelname)-8s] [%(name)s:%(funcName)s:%(lineno)d] %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )

        # Set up root logger
        root_logger = logging.getLogger()
        root_logger.setLevel(cls._get_log_level())

        # Clear existing handlers to avoid duplicates
        for handler in root_logger.handlers[:]:
            root_logger.removeHandler(handler)

        # Console handler
        if cls._is_console_logging_enabled():
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setLevel(cls._get_console_log_level())
            console_handler.setFormatter(simple_formatter)
            root_logger.addHandler(console_handler)

        # File handler with rotation
        if cls._is_file_logging_enabled():
            try:
                file_handler = cls._create_file_handler(detailed_formatter)
                file_handler.setLevel(logging.DEBUG)  # Always capture all levels in file
                root_logger.addHandler(file_handler)
            except (IOError, OSError) as e:
                # Fallback to console only if file logging fails
                fallback_handler = logging.StreamHandler(sys.stderr)
                fallback_handler.setLevel(logging.WARNING)
                fallback_handler.setFormatter(simple_formatter)
                root_logger.addHandler(fallback_handler)
                root_logger.warning(f"Failed to set up file logging: {e}. Using console logging only.")

        # Prevent propagation to avoid duplicate logs
        root_logger.propagate = False
        cls._configured = True

    @classmethod
    def _get_log_level(cls) -> int:
        """Get the overall log level from environment variables."""
        level_str = os.getenv('LOG_LEVEL', 'INFO').upper()
        return getattr(logging, level_str, logging.INFO)

    @classmethod
    def _get_console_log_level(cls) -> int:
        """Get the console log level from environment variables."""
        level_str = os.getenv('CONSOLE_LOG_LEVEL', os.getenv('LOG_LEVEL', 'INFO')).upper()
        return getattr(logging, level_str, logging.INFO)

    @classmethod
    def _is_console_logging_enabled(cls) -> bool:
        """Check if console logging is enabled."""
        return os.getenv('CONSOLE_LOGGING_ENABLED', 'true').lower() == 'true'

    @classmethod
    def _is_file_logging_enabled(cls) -> bool:
        """Check if file logging is enabled."""
        return os.getenv('LOG_FILE_ENABLED', 'true').lower() == 'true'

    @classmethod
    def _create_file_handler(cls, formatter: logging.Formatter) -> logging.Handler:
        """Create a rotating file handler."""
        log_dir = Path(os.getenv('LOG_DIR', cls._default_log_dir))
        
        try:
            log_dir.mkdir(exist_ok=True, parents=True)
        except (OSError, PermissionError) as e:
            raise IOError(f"Cannot create log directory {log_dir}: {e}")

        log_file = log_dir / cls._default_log_file

        # Get rotation settings from environment
        max_bytes = int(os.getenv('LOG_MAX_BYTES', '10485760'))  # 10MB default
        backup_count = int(os.getenv('LOG_BACKUP_COUNT', '5'))

        # Use RotatingFileHandler for size-based rotation
        handler = logging.handlers.RotatingFileHandler(
            log_file,
            maxBytes=max_bytes,
            backupCount=backup_count,
            encoding='utf-8'
        )

        handler.setFormatter(formatter)
        return handler

    @classmethod
    def configure_from_args(cls, args: argparse.Namespace) -> None:
        """
        Configure logging based on command line arguments.

        Args:
            args: Parsed command line arguments with logging options
        """
        # Update environment variables based on args
        if hasattr(args, 'verbose') and args.verbose:
            os.environ['LOG_LEVEL'] = 'DEBUG'
            os.environ['CONSOLE_LOG_LEVEL'] = 'DEBUG'
        elif hasattr(args, 'log_level'):
            os.environ['LOG_LEVEL'] = args.log_level
            
        if hasattr(args, 'quiet') and args.quiet:
            os.environ['CONSOLE_LOGGING_ENABLED'] = 'false'
            
        if hasattr(args, 'log_file'):
            os.environ['LOG_FILE_ENABLED'] = 'true' if args.log_file else 'false'
            
        if hasattr(args, 'log_dir'):
            os.environ['LOG_DIR'] = args.log_dir

        # Reconfigure logging with new settings
        cls._configured = False
        cls._setup_logging()

    @classmethod
    def shutdown(cls) -> None:
        """Clean up and shutdown all logging handlers."""
        logging.shutdown()
        cls._configured = False
        cls._loggers.clear()


def get_logger(name: str) -> logging.Logger:
    """
    Convenience function to get a logger.

    Args:
        name: Logger name (typically __name__ of the calling module)

    Returns:
        Configured logger instance
    """
    return LoggerFactory.get_logger(name)


def setup_logging_from_env() -> None:
    """Set up logging configuration from environment variables."""
    LoggerFactory._setup_logging()


# Convenience functions for common logging patterns
def log_function_entry(logger: logging.Logger, func_name: str, *args, **kwargs) -> None:
    """Log function entry with parameters."""
    if logger.isEnabledFor(logging.DEBUG):
        params = []
        if args:
            # Mask sensitive arguments
            masked_args = ['*' * 8 if 'password' in str(arg).lower() or 'key' in str(arg).lower() else str(arg) for arg in args]
            params.append(f"args={masked_args}")
        if kwargs:
            # Mask sensitive keyword arguments
            masked_kwargs = {k: '********' if any(sensitive in k.lower() for sensitive in ['password', 'key', 'secret', 'token']) else v 
                           for k, v in kwargs.items()}
            params.append(f"kwargs={masked_kwargs}")

        param_str = ", ".join(params) if params else "no parameters"
        logger.debug(f"Entering {func_name}({param_str})")


def log_function_exit(logger: logging.Logger, func_name: str, return_value: Any = None) -> None:
    """Log function exit with return value."""
    if logger.isEnabledFor(logging.DEBUG):
        if return_value is not None:
            # Mask sensitive return values
            if isinstance(return_value, str) and any(sensitive in return_value.lower() for sensitive in ['password', 'key', 'secret']):
                masked_value = '********'
            else:
                masked_value = return_value
            logger.debug(f"Exiting {func_name} with return value: {masked_value}")
        else:
            logger.debug(f"Exiting {func_name}")


def log_exception(logger: logging.Logger, exc: Exception, message: str = "Exception occurred", 
                  level: int = logging.ERROR) -> None:
    """
    Log an exception with full traceback.
    
    Args:
        logger: Logger instance
        exc: Exception to log
        message: Custom message prefix
        level: Log level (default: ERROR)
    """
    logger.log(level, f"{message}: {exc}", exc_info=True)


def add_logging_arguments(parser: argparse.ArgumentParser) -> None:
    """
    Add logging-related command line arguments to an argument parser.
    
    Args:
        parser: Argument parser to add logging options to
    """
    logging_group = parser.add_argument_group('Logging Options')
    logging_group.add_argument(
        '--verbose', '-v', 
        action='store_true',
        help='Enable verbose output (DEBUG level)'
    )
    logging_group.add_argument(
        '--quiet', '-q',
        action='store_true', 
        help='Disable console output'
    )
    logging_group.add_argument(
        '--log-level',
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
        default='INFO',
        help='Set the logging level'
    )
    logging_group.add_argument(
        '--log-dir',
        type=str,
        default='./logs',
        help='Directory for log files'
    )
    logging_group.add_argument(
        '--no-log-file',
        action='store_true',
        help='Disable logging to file'
    )


# Example usage and migration guide for replacing print statements
class PrintToLogMigration:
    """
    Helper class to demonstrate how to migrate from print() to logging.
    """
    
    @staticmethod
    def migration_examples():
        """
        Examples showing how to replace print statements with proper logging.
        """
        logger = get_logger(__name__)
        
        # OLD: print("Starting application...")
        # NEW:
        logger.info("Starting application...")
        
        # OLD: print(f"Connected to network: {network_name}")
        # NEW:
        logger.info("Connected to network: %s", network_name)
        
        # OLD: print("Warning: Weak signal strength")
        # NEW:
        logger.warning("Weak signal strength")
        
        # OLD: print(f"Error: {error_message}")
        # NEW:
        logger.error("Connection failed: %s", error_message)
        
        # OLD: print("Debug info: ", variable)
        # NEW:
        logger.debug("Variable state: %s", variable)
        
        # OLD: print("Configuration loaded successfully")
        # NEW:
        logger.info("Configuration loaded successfully")


# Context manager for temporary log level changes
class TemporaryLogLevel:
    """Context manager for temporary log level changes."""
    
    def __init__(self, logger: logging.Logger, level: int):
        self.logger = logger
        self.new_level = level
        self.original_level = logger.level
        self.original_handlers_levels = []
        
    def __enter__(self):
        # Store original levels
        for handler in self.logger.handlers:
            self.original_handlers_levels.append(handler.level)
            handler.setLevel(self.new_level)
        
        self.logger.setLevel(self.new_level)
        return self
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        # Restore original levels
        self.logger.setLevel(self.original_level)
        for handler, original_level in zip(self.logger.handlers, self.original_handlers_levels):
            handler.setLevel(original_level)


def initialize_logging(verbose: bool = False, quiet: bool = False, 
                      log_dir: Optional[str] = None) -> None:
    """
    Initialize logging with specified settings.
    
    Args:
        verbose: Enable verbose logging
        quiet: Disable console output
        log_dir: Directory for log files
    """
    if verbose:
        os.environ['LOG_LEVEL'] = 'DEBUG'
        os.environ['CONSOLE_LOG_LEVEL'] = 'DEBUG'
    
    if quiet:
        os.environ['CONSOLE_LOGGING_ENABLED'] = 'false'
    
    if log_dir:
        os.environ['LOG_DIR'] = log_dir
    
    setup_logging_from_env()
    
    logger = get_logger(__name__)
    logger.info("Logging system initialized")
    logger.debug("Verbose logging enabled: %s", verbose)
    logger.debug("Console logging enabled: %s", not quiet)
    logger.debug("Log directory: %s", log_dir or os.getenv('LOG_DIR', './logs'))


if __name__ == "__main__":
    # Example usage and test
    parser = argparse.ArgumentParser(description='Logging system test')
    add_logging_arguments(parser)
    args = parser.parse_args()
    
    # Configure logging from command line arguments
    LoggerFactory.configure_from_args(args)
    
    # Get a logger
    logger = get_logger(__name__)
    
    # Test different log levels
    logger.debug("This is a debug message")
    logger.info("This is an info message")
    logger.warning("This is a warning message")
    logger.error("This is an error message")
    logger.critical("This is a critical message")
    
    # Test function logging
    log_function_entry(logger, "test_function", "arg1", password="secret123")
    log_function_exit(logger, "test_function", "sensitive_data")
    
    # Test exception logging
    try:
        raise ValueError("Test exception for logging")
    except ValueError as e:
        log_exception(logger, e, "Test exception occurred"dss