"""
Security Audit Management Command.

Runs comprehensive security checks on the Django application and generates
a security audit report.

Usage:
    python manage.py security_audit
    python manage.py security_audit --output report.txt
    python manage.py security_audit --verbose
"""

from django.conf import settings
from django.core.checks import Tags, registry
from django.core.management.base import BaseCommand


class Command(BaseCommand):
    help = "Run security audit and generate a report"

    def add_arguments(self, parser):
        parser.add_argument(
            "--output",
            type=str,
            help="Output file for the security report",
        )
        parser.add_argument(
            "--verbose",
            action="store_true",
            help="Show detailed information for each check",
        )

    def handle(self, *args, **options):
        self.verbose = options.get("verbose", False)
        output_file = options.get("output")

        report_lines = []

        self.log("=" * 60, report_lines)
        self.log("ThrillWiki Security Audit Report", report_lines)
        self.log("=" * 60, report_lines)
        self.log("", report_lines)

        # Run Django's built-in security checks
        self.log("Running Django Security Checks...", report_lines)
        self.log("-" * 40, report_lines)
        self.run_django_checks(report_lines)

        # Run custom configuration checks
        self.log("", report_lines)
        self.log("Configuration Analysis...", report_lines)
        self.log("-" * 40, report_lines)
        self.check_configuration(report_lines)

        # Run middleware checks
        self.log("", report_lines)
        self.log("Middleware Analysis...", report_lines)
        self.log("-" * 40, report_lines)
        self.check_middleware(report_lines)

        # Summary
        self.log("", report_lines)
        self.log("=" * 60, report_lines)
        self.log("Audit Complete", report_lines)
        self.log("=" * 60, report_lines)

        # Write to file if specified
        if output_file:
            with open(output_file, "w") as f:
                f.write("\n".join(report_lines))
            self.stdout.write(self.style.SUCCESS(f"\nReport saved to: {output_file}"))

    def log(self, message, report_lines):
        """Log message to both stdout and report."""
        self.stdout.write(message)
        report_lines.append(message)

    def run_django_checks(self, report_lines):
        """Run Django's security checks."""
        errors = registry.run_checks(tags=[Tags.security])

        if not errors:
            self.log(self.style.SUCCESS("  ✓ All Django security checks passed"), report_lines)
        else:
            for error in errors:
                prefix = self.style.ERROR("  ✗ ERROR") if error.is_serious() else self.style.WARNING("  ! WARNING")

                self.log(f"{prefix}: {error.msg}", report_lines)
                if error.hint and self.verbose:
                    self.log(f"    Hint: {error.hint}", report_lines)

    def check_configuration(self, report_lines):
        """Check various configuration settings."""
        checks = [
            ("DEBUG mode", not settings.DEBUG, "DEBUG should be False"),
            ("SECRET_KEY length", len(settings.SECRET_KEY) >= 50, f"Length: {len(settings.SECRET_KEY)}"),
            (
                "ALLOWED_HOSTS",
                bool(settings.ALLOWED_HOSTS) and "*" not in settings.ALLOWED_HOSTS,
                str(settings.ALLOWED_HOSTS),
            ),
            (
                "CSRF_TRUSTED_ORIGINS",
                bool(getattr(settings, "CSRF_TRUSTED_ORIGINS", [])),
                str(getattr(settings, "CSRF_TRUSTED_ORIGINS", [])),
            ),
            (
                "X_FRAME_OPTIONS",
                getattr(settings, "X_FRAME_OPTIONS", "") in ("DENY", "SAMEORIGIN"),
                str(getattr(settings, "X_FRAME_OPTIONS", "Not set")),
            ),
            (
                "SECURE_CONTENT_TYPE_NOSNIFF",
                getattr(settings, "SECURE_CONTENT_TYPE_NOSNIFF", False),
                str(getattr(settings, "SECURE_CONTENT_TYPE_NOSNIFF", False)),
            ),
            (
                "SECURE_BROWSER_XSS_FILTER",
                getattr(settings, "SECURE_BROWSER_XSS_FILTER", False),
                str(getattr(settings, "SECURE_BROWSER_XSS_FILTER", False)),
            ),
            (
                "SESSION_COOKIE_HTTPONLY",
                getattr(settings, "SESSION_COOKIE_HTTPONLY", True),
                str(getattr(settings, "SESSION_COOKIE_HTTPONLY", "Not set")),
            ),
            (
                "CSRF_COOKIE_HTTPONLY",
                getattr(settings, "CSRF_COOKIE_HTTPONLY", True),
                str(getattr(settings, "CSRF_COOKIE_HTTPONLY", "Not set")),
            ),
        ]

        # Production-only checks
        if not settings.DEBUG:
            checks.extend(
                [
                    (
                        "SECURE_SSL_REDIRECT",
                        getattr(settings, "SECURE_SSL_REDIRECT", False),
                        str(getattr(settings, "SECURE_SSL_REDIRECT", False)),
                    ),
                    (
                        "SESSION_COOKIE_SECURE",
                        getattr(settings, "SESSION_COOKIE_SECURE", False),
                        str(getattr(settings, "SESSION_COOKIE_SECURE", False)),
                    ),
                    (
                        "CSRF_COOKIE_SECURE",
                        getattr(settings, "CSRF_COOKIE_SECURE", False),
                        str(getattr(settings, "CSRF_COOKIE_SECURE", False)),
                    ),
                    (
                        "SECURE_HSTS_SECONDS",
                        getattr(settings, "SECURE_HSTS_SECONDS", 0) >= 31536000,
                        str(getattr(settings, "SECURE_HSTS_SECONDS", 0)),
                    ),
                ]
            )

        for name, is_secure, value in checks:
            status = self.style.SUCCESS("✓") if is_secure else self.style.WARNING("!")

            msg = f"  {status} {name}"
            if self.verbose:
                msg += f" ({value})"

            self.log(msg, report_lines)

    def check_middleware(self, report_lines):
        """Check security-related middleware is properly configured."""
        middleware = getattr(settings, "MIDDLEWARE", [])

        required_middleware = [
            ("django.middleware.security.SecurityMiddleware", "SecurityMiddleware"),
            ("django.middleware.csrf.CsrfViewMiddleware", "CSRF Middleware"),
            ("django.middleware.clickjacking.XFrameOptionsMiddleware", "X-Frame-Options"),
        ]

        custom_security_middleware = [
            ("apps.core.middleware.security_headers.SecurityHeadersMiddleware", "Security Headers"),
            ("apps.core.middleware.rate_limiting.AuthRateLimitMiddleware", "Rate Limiting"),
        ]

        # Check required middleware
        for mw_path, mw_name in required_middleware:
            if mw_path in middleware:
                self.log(f"  {self.style.SUCCESS('✓')} {mw_name} is enabled", report_lines)
            else:
                self.log(f"  {self.style.ERROR('✗')} {mw_name} is NOT enabled", report_lines)

        # Check custom security middleware
        for mw_path, mw_name in custom_security_middleware:
            if mw_path in middleware:
                self.log(f"  {self.style.SUCCESS('✓')} {mw_name} is enabled", report_lines)
            else:
                self.log(f"  {self.style.WARNING('!')} {mw_name} is not enabled (optional)", report_lines)

        # Check middleware order
        try:
            security_idx = middleware.index("django.middleware.security.SecurityMiddleware")
            session_idx = middleware.index("django.contrib.sessions.middleware.SessionMiddleware")

            if security_idx < session_idx:
                self.log(f"  {self.style.SUCCESS('✓')} Middleware ordering is correct", report_lines)
            else:
                self.log(
                    f"  {self.style.WARNING('!')} SecurityMiddleware should come before SessionMiddleware", report_lines
                )
        except ValueError:
            pass  # Middleware not found, already reported above
