"""
Django Integration for Storm Logger

This module provides Django-specific logging functionality, extending Storm Logger
with Django framework integration features.

Key Components:
- DjangoStormLogger: Django-specific logger class
- Configuration functions for Django settings
- Context detection for Django components
- Integration helpers for Django projects
"""

import logging
import logging.config
from pathlib import Path
from typing import Any

from ..config import Framework, StormLoggerConfig
from ..core.base import check_optional_dependency, create_base_logging_config
from ..core.logger import StormLogger


class DjangoStormLogger(StormLogger):
    """
    Django-specific Storm Logger with enhanced Django integration.

    This class extends StormLogger with Django-specific functionality:
    - Django debug filters for environment-aware logging
    - Admin email handlers for production error notifications
    - Django-specific context detection for better log categorization
    - Seamless integration with Django settings

    Example:
        logger = DjangoStormLogger(__name__)
        logger.info("Processing Django request")
    """

    def __init__(
        self,
        name: str,
        config: StormLoggerConfig | None = None,
        auto_detect_context: bool = True,
    ):
        """
        Initialize Django-specific Storm Logger.

        Args:
            name: Logger name (typically __name__)
            config: Optional Storm Logger configuration
            auto_detect_context: Whether to automatically detect Django context
        """
        super().__init__(name, config, auto_detect_context)

        # Ensure framework is set to Django
        if self.config.framework != Framework.DJANGO:
            self.config.framework = Framework.DJANGO

    def _configure_handlers(self) -> None:
        """Configure Django-specific log handlers."""
        logging_config = create_django_logging_config(self.config)

        # Apply the logging configuration
        logging.config.dictConfig(logging_config)


# Django-specific context patterns for better log categorization
DJANGO_CONTEXT_PATTERNS = {
    "view": ["views.py", "view", "View"],
    "model": ["models.py", "model", "Model"],
    "form": ["forms.py", "form", "Form"],
    "admin": ["admin.py", "admin", "Admin"],
    "middleware": ["middleware.py", "middleware", "Middleware"],
    "management": ["management/commands/", "handle"],
    "template": ["templates/", ".html"],
    "static": ["static/", ".css", ".js"],
    "test": ["test_", "tests.py", "TestCase"],
    "migration": ["migrations/", "Migration"],
    "signal": ["signals.py", "signal", "Signal"],
    "serializer": ["serializers.py", "serializer", "Serializer"],
    "url": ["urls.py", "urlpatterns"],
    "settings": ["settings.py", "settings"],
    "wsgi": ["wsgi.py", "application"],
    "asgi": ["asgi.py", "application"],
}


def create_django_logging_config(config: StormLoggerConfig) -> dict[str, Any]:
    """
    Create Django-specific logging configuration dictionary.

    This function generates a complete logging configuration that integrates
    Storm Logger with Django's logging system. It includes Django-specific
    filters, handlers, and loggers while maintaining Storm Logger's features.

    Args:
        config: Storm Logger configuration object

    Returns:
        Django-compatible logging configuration dictionary

    Example:
        config = DjangoStormLoggerConfig()
        logging_dict = create_django_logging_config(config)
        # Use in Django settings: LOGGING = logging_dict
    """
    # Start with base Storm Logger configuration
    logging_config = create_base_logging_config(config)

    # Check if we have Django available
    is_django_config = hasattr(config, "app_log_levels")  # DjangoStormLoggerConfig indicator
    has_django = is_django_config or check_optional_dependency("django")

    if not has_django:
        return logging_config

    # Add Django-specific components
    _add_django_filters(logging_config)
    _add_django_handlers(logging_config, config)
    _add_django_loggers(logging_config, config)
    _configure_app_specific_loggers(logging_config, config)
    _add_production_enhancements(logging_config, config)

    return logging_config


def _add_django_filters(logging_config: dict[str, Any]) -> None:
    """Add Django-specific log filters."""
    logging_config["filters"].update(
        {
            "require_debug_true": {
                "()": "django.utils.log.RequireDebugTrue",
            },
            "require_debug_false": {
                "()": "django.utils.log.RequireDebugFalse",
            },
        }
    )


def _add_django_handlers(logging_config: dict[str, Any], config: StormLoggerConfig) -> None:
    """Add Django-specific handlers based on configuration."""
    # Production handlers
    if config.production_mode:
        logging_config["handlers"]["mail_admins"] = {
            "level": "ERROR",
            "class": "django.utils.log.AdminEmailHandler",
            "filters": ["require_debug_false"],
            "formatter": "verbose",
            "include_html": True,
        }

        logging_config["handlers"]["syslog"] = {
            "level": "INFO",
            "class": "logging.handlers.SysLogHandler",
            "formatter": "standard",
            "filters": ["require_debug_false"],
            "address": "/dev/log",  # Standard syslog socket on Linux
        }

    # Debug handlers
    if config.debug_mode:
        debug_log_file = (config.log_directory or Path(".")) / "app" / "debug.log"
        logging_config["handlers"]["debug_file"] = {
            "level": "DEBUG",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": str(debug_log_file),
            "maxBytes": config.max_file_size * 2,  # 20MB
            "backupCount": 2,
            "formatter": "verbose",
            "encoding": "utf-8",
            "filters": ["require_debug_true"],
        }

    # Django main log file
    django_log_file = (config.log_directory or Path(".")) / "django" / "django.log"
    logging_config["handlers"]["django_file"] = {
        "level": "INFO",
        "class": "logging.handlers.RotatingFileHandler",
        "filename": str(django_log_file),
        "maxBytes": config.max_file_size // 2,  # 5MB
        "backupCount": 3,
        "formatter": "verbose",
        "encoding": "utf-8",
    }


def _add_django_loggers(logging_config: dict[str, Any], config: StormLoggerConfig) -> None:
    """Configure Django framework loggers."""
    # Main Django logger
    logging_config["loggers"]["django"] = {
        "handlers": ["console", "django_file", "error_file"],
        "level": "INFO",
        "propagate": False,
    }

    # Django request logger
    handlers = ["console_error", "error_file"]
    if config.production_mode:
        handlers.append("mail_admins")

    logging_config["loggers"]["django.request"] = {
        "handlers": handlers,
        "level": "ERROR",
        "propagate": False,
    }

    # Django security logger
    logging_config["loggers"]["django.security"] = {
        "handlers": handlers,
        "level": "WARNING",
        "propagate": False,
    }

    # Django database logger
    db_handlers = ["debug_file"] if config.debug_mode else []
    logging_config["loggers"]["django.db.backends"] = {
        "handlers": db_handlers,
        "level": "DEBUG" if config.debug_mode else "INFO",
        "propagate": False,
    }


def _configure_app_specific_loggers(
    logging_config: dict[str, Any], config: StormLoggerConfig
) -> None:
    """Configure app-specific loggers based on DjangoStormLoggerConfig."""
    # Storm app loggers
    storm_app_loggers = [
        "storm.base",
        "storm.billing",
        "storm.auth",
        "storm.invoicing",
        "storm.dashboard",
        "storm.business_logic",
        "storm.business_data",
    ]

    handlers = ["console", "app_file", "error_file"]
    if config.debug_mode:
        handlers.append("debug_file")

    for logger_name in storm_app_loggers:
        logging_config["loggers"][logger_name] = {
            "handlers": handlers,
            "level": config.log_level.value,
            "propagate": False,
        }

    # Custom app log levels from DjangoStormLoggerConfig
    if hasattr(config, "app_log_levels"):
        for app_name, log_level in config.app_log_levels.items():
            if app_name not in logging_config["loggers"]:
                logging_config["loggers"][app_name] = {
                    "handlers": ["console", "app_file", "error_file"],
                    "level": log_level.value,
                    "propagate": False,
                }
            else:
                # Update existing logger's level
                logging_config["loggers"][app_name]["level"] = log_level.value

    # Excluded apps with ERROR level only
    if hasattr(config, "excluded_apps"):
        for app_name in config.excluded_apps:
            if app_name not in logging_config["loggers"]:
                logging_config["loggers"][app_name] = {
                    "handlers": ["console", "error_file"],
                    "level": "ERROR",
                    "propagate": False,
                }

    # Third-party loggers
    logging_config["loggers"]["celery"] = {
        "handlers": ["console", "app_file", "error_file"],
        "level": "INFO",
        "propagate": False,
    }


def _add_production_enhancements(logging_config: dict[str, Any], config: StormLoggerConfig) -> None:
    """Add production-specific enhancements to all loggers."""
    if config.production_mode:
        for logger_config in logging_config["loggers"].values():
            # Ensure handlers list exists
            if "handlers" not in logger_config:
                logger_config["handlers"] = []

            # Add syslog if not present
            if "syslog" not in logger_config["handlers"]:
                logger_config["handlers"].append("syslog")


def configure_django_logging(config: StormLoggerConfig | None = None) -> None:
    """
    Configure Django logging with Storm Logger.

    This function sets up Django-specific logging configuration
    that can be used in Django settings.py.

    Args:
        config: Optional Storm Logger configuration

    Example:
        # In Django settings.py
        from storm_logger.integrations.django import configure_django_logging
        configure_django_logging()
    """
    from ..config import get_config, set_config

    if config is None:
        config = get_config()

    # Ensure framework is set to Django
    config.framework = Framework.DJANGO
    set_config(config)

    # Create Django logging configuration
    logging_config = create_django_logging_config(config)

    # Set up directories
    config.create_log_directories()

    # Apply configuration
    logging.config.dictConfig(logging_config)


def get_django_logging_config(config: StormLoggerConfig | None = None) -> dict[str, Any]:
    """
    Get Django logging configuration dictionary for Django settings.

    This function returns a Django-compatible logging configuration
    that can be directly used in Django's LOGGING setting.

    Args:
        config: Optional Storm Logger configuration

    Returns:
        Django logging configuration dictionary

    Example:
        # In Django settings.py
        from storm_logger.integrations.django import get_django_logging_config
        LOGGING = get_django_logging_config()
    """
    from ..config import get_config

    if config is None:
        config = get_config()

    # Ensure framework is set to Django
    config.framework = Framework.DJANGO

    # Create and return Django logging configuration
    return create_django_logging_config(config)


def integrate_with_django_settings(settings_module: Any) -> None:
    """
    Integrate Storm Logger with Django settings module.

    This function modifies Django settings to use Storm Logger
    as the default logging system and adds Storm Logger to
    installed apps if needed.

    Args:
        settings_module: Django settings module object

    Example:
        # In Django settings.py
        from storm_logger.integrations.django import integrate_with_django_settings
        integrate_with_django_settings(globals())
    """
    from ..config import get_config

    config = get_config()
    config.framework = Framework.DJANGO

    # Set Django logging configuration
    settings_module.LOGGING = get_django_logging_config(config)

    # Add Storm Logger to installed apps if not already present
    if not hasattr(settings_module, "INSTALLED_APPS"):
        settings_module.INSTALLED_APPS = []

    if "storm_logger" not in settings_module.INSTALLED_APPS:
        settings_module.INSTALLED_APPS.append("storm_logger")


def detect_django_context(frame_info: Any) -> str:
    """
    Detect Django-specific context from frame information.

    This function analyzes Python frame information to determine
    the Django component context (view, model, form, etc.).

    Args:
        frame_info: Python frame information object

    Returns:
        Django context string (e.g., "django.view", "django.model")

    Example:
        context = detect_django_context(inspect.currentframe())
        # Returns: "django.view" if called from a view
    """
    filename = frame_info.filename.lower()
    function_name = frame_info.function.lower()

    # Check Django-specific patterns
    for context, patterns in DJANGO_CONTEXT_PATTERNS.items():
        for pattern in patterns:
            if pattern in filename or pattern in function_name:
                return f"django.{context}"

    # Check for Django app context
    if "/apps/" in filename or "/django/" in filename:
        return "django.app"

    # Default Django context
    return "django.system"
