"""
Management command to optimize static files (minification and compression).

This command processes JavaScript and CSS files to create minified versions
for production use, reducing file sizes and improving page load times.

Usage:
    python manage.py optimize_static
    python manage.py optimize_static --dry-run
    python manage.py optimize_static --force
"""

from pathlib import Path

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError


class Command(BaseCommand):
    help = "Optimize static files by creating minified versions of JS and CSS files"

    def add_arguments(self, parser):
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Show what would be done without making changes",
        )
        parser.add_argument(
            "--force",
            action="store_true",
            help="Overwrite existing minified files",
        )
        parser.add_argument(
            "--js-only",
            action="store_true",
            help="Only process JavaScript files",
        )
        parser.add_argument(
            "--css-only",
            action="store_true",
            help="Only process CSS files",
        )

    def handle(self, *args, **options):
        dry_run = options["dry_run"]
        force = options["force"]
        js_only = options["js_only"]
        css_only = options["css_only"]

        # Check for required dependencies
        try:
            import rjsmin
        except ImportError:
            rjsmin = None
            self.stdout.write(self.style.WARNING("rjsmin not installed. Install with: pip install rjsmin"))

        try:
            import rcssmin
        except ImportError:
            rcssmin = None
            self.stdout.write(self.style.WARNING("rcssmin not installed. Install with: pip install rcssmin"))

        if not rjsmin and not rcssmin:
            raise CommandError(
                "Neither rjsmin nor rcssmin is installed. " "Install at least one: pip install rjsmin rcssmin"
            )

        # Get static file directories
        static_dirs = list(settings.STATICFILES_DIRS) + [settings.STATIC_ROOT]
        static_dirs = [Path(d) for d in static_dirs if d and Path(d).exists()]

        if not static_dirs:
            raise CommandError("No valid static file directories found")

        total_js_saved = 0
        total_css_saved = 0
        js_files_processed = 0
        css_files_processed = 0

        for static_dir in static_dirs:
            self.stdout.write(f"Processing directory: {static_dir}")

            # Process JavaScript files
            if not css_only and rjsmin:
                js_dir = static_dir / "js"
                if js_dir.exists():
                    saved, count = self._process_js_files(js_dir, rjsmin, dry_run, force)
                    total_js_saved += saved
                    js_files_processed += count

            # Process CSS files
            if not js_only and rcssmin:
                css_dir = static_dir / "css"
                if css_dir.exists():
                    saved, count = self._process_css_files(css_dir, rcssmin, dry_run, force)
                    total_css_saved += saved
                    css_files_processed += count

        # Summary
        self.stdout.write("\n" + "=" * 60)
        self.stdout.write(self.style.SUCCESS("Static file optimization complete!"))
        self.stdout.write(f"JavaScript files processed: {js_files_processed}")
        self.stdout.write(f"CSS files processed: {css_files_processed}")
        self.stdout.write(f"Total JS savings: {self._format_size(total_js_saved)}")
        self.stdout.write(f"Total CSS savings: {self._format_size(total_css_saved)}")

        if dry_run:
            self.stdout.write(self.style.WARNING("\nDry run - no files were modified"))

    def _process_js_files(self, js_dir, rjsmin, dry_run, force):
        """Process JavaScript files for minification."""
        total_saved = 0
        files_processed = 0

        for js_file in js_dir.glob("**/*.js"):
            # Skip already minified files
            if js_file.name.endswith(".min.js"):
                continue

            min_file = js_file.with_suffix(".min.js")

            # Skip if minified version exists and not forcing
            if min_file.exists() and not force:
                self.stdout.write(f"  Skipping {js_file.name} (min version exists)")
                continue

            try:
                original_content = js_file.read_text(encoding="utf-8")
                original_size = len(original_content.encode("utf-8"))

                # Minify
                minified_content = rjsmin.jsmin(original_content)
                minified_size = len(minified_content.encode("utf-8"))

                savings = original_size - minified_size
                savings_percent = (savings / original_size * 100) if original_size > 0 else 0

                if not dry_run:
                    min_file.write_text(minified_content, encoding="utf-8")

                self.stdout.write(
                    f"  {js_file.name}: {self._format_size(original_size)} -> "
                    f"{self._format_size(minified_size)} "
                    f"(-{savings_percent:.1f}%)"
                )

                total_saved += savings
                files_processed += 1

            except Exception as e:
                self.stdout.write(self.style.ERROR(f"  Error processing {js_file.name}: {e}"))

        return total_saved, files_processed

    def _process_css_files(self, css_dir, rcssmin, dry_run, force):
        """Process CSS files for minification."""
        total_saved = 0
        files_processed = 0

        for css_file in css_dir.glob("**/*.css"):
            # Skip already minified files
            if css_file.name.endswith(".min.css"):
                continue

            min_file = css_file.with_suffix(".min.css")

            # Skip if minified version exists and not forcing
            if min_file.exists() and not force:
                self.stdout.write(f"  Skipping {css_file.name} (min version exists)")
                continue

            try:
                original_content = css_file.read_text(encoding="utf-8")
                original_size = len(original_content.encode("utf-8"))

                # Minify
                minified_content = rcssmin.cssmin(original_content)
                minified_size = len(minified_content.encode("utf-8"))

                savings = original_size - minified_size
                savings_percent = (savings / original_size * 100) if original_size > 0 else 0

                if not dry_run:
                    min_file.write_text(minified_content, encoding="utf-8")

                self.stdout.write(
                    f"  {css_file.name}: {self._format_size(original_size)} -> "
                    f"{self._format_size(minified_size)} "
                    f"(-{savings_percent:.1f}%)"
                )

                total_saved += savings
                files_processed += 1

            except Exception as e:
                self.stdout.write(self.style.ERROR(f"  Error processing {css_file.name}: {e}"))

        return total_saved, files_processed

    def _format_size(self, size_bytes):
        """Format byte size to human-readable format."""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        else:
            return f"{size_bytes / (1024 * 1024):.2f} MB"
