"""
Management command to export database data to Django fixture format and compress.

Usage:
    python manage.py export_data --compress
"""
import json
import os
import zipfile
from django.core.management.base import BaseCommand, CommandError
from django.apps import apps
from django.core import serializers
from datetime import datetime


class Command(BaseCommand):
    help = 'Export database data to compressed JSON fixtures'

    def add_arguments(self, parser):
        parser.add_argument(
            '--output-dir',
            type=str,
            default='./database_export',
            help='Directory to export JSON files to'
        )
        parser.add_argument(
            '--compress',
            action='store_true',
            help='Create a compressed ZIP file of all exports'
        )
        parser.add_argument(
            '--apps',
            type=str,
            nargs='+',
            help='Specific apps to export (e.g., complaints organizations accounts)'
        )
        parser.add_argument(
            '--exclude-apps',
            type=str,
            nargs='+',
            default=['contenttypes', 'auth', 'admin', 'sessions', 'django_celery_beat'],
            help='Apps to exclude from export'
        )

    def handle(self, *args, **options):
        output_dir = options['output_dir']
        include_apps = options['apps']
        exclude_apps = options['exclude_apps']
        do_compress = options['compress']

        # Create output directory
        os.makedirs(output_dir, exist_ok=True)

        # Get all models
        all_models = apps.get_models()

        # Group models by app
        models_by_app = {}
        for model in all_models:
            app_label = model._meta.app_label
            
            # Skip excluded apps
            if app_label in exclude_apps:
                continue
            
            # Skip if specific apps requested and this isn't one of them
            if include_apps and app_label not in include_apps:
                continue
            
            if app_label not in models_by_app:
                models_by_app[app_label] = []
            models_by_app[app_label].append(model)

        # Export data
        total_exported = 0
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        fixture_files = []
        
        self.stdout.write(self.style.SUCCESS(f'Exporting data to: {output_dir}'))
        self.stdout.write(f'Found {len(models_by_app)} apps to export\n')

        for app_label, models in models_by_app.items():
            app_dir = os.path.join(output_dir, app_label)
            os.makedirs(app_dir, exist_ok=True)
            
            app_count = 0
            all_objects = []
            
            for model in models:
                model_name = model._meta.model_name
                
                # Get all objects
                queryset = model.objects.all()
                count = queryset.count()
                if count == 0:
                    continue
                
                try:
                    # Serialize to Django fixture format
                    serialized = serializers.serialize('json', queryset)
                    data = json.loads(serialized)
                    all_objects.extend(data)
                    app_count += count
                    total_exported += count
                    
                    self.stdout.write(f'  ✓ {app_label}.{model_name}: {count} records')
                except Exception as e:
                    self.stdout.write(self.style.WARNING(f'  ⊘ {app_label}.{model_name}: Error - {str(e)}'))

            # Write app fixture file (Django format)
            if all_objects:
                output_file = os.path.join(app_dir, f'{app_label}_fixture.json')
                with open(output_file, 'w', encoding='utf-8') as f:
                    json.dump(all_objects, f, indent=2, ensure_ascii=False)
                
                fixture_files.append(output_file)
                
                self.stdout.write(self.style.SUCCESS(f'  → Exported to: {output_file} ({app_count} records)\n'))

        # Create compressed ZIP file
        if do_compress:
            zip_filename = os.path.join(output_dir, f'database_export_{timestamp}.zip')
            
            self.stdout.write(self.style.SUCCESS(f'\nCreating compressed archive: {zip_filename}'))
            
            with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for root, dirs, files in os.walk(output_dir):
                    for file in files:
                        if file.endswith('.zip'):
                            continue  # Skip the zip file itself
                        
                        file_path = os.path.join(root, file)
                        arcname = os.path.relpath(file_path, output_dir)
                        zipf.write(file_path, arcname)
                        
                        # Print progress for large files
                        file_size = os.path.getsize(file_path)
                        if file_size > 1024 * 1024:  # > 1MB
                            self.stdout.write(f'  ✓ Added: {arcname} ({file_size / (1024*1024):.1f} MB)')
            
            zip_size = os.path.getsize(zip_filename)
            self.stdout.write(self.style.SUCCESS(f'  → ZIP created: {zip_filename} ({zip_size / (1024*1024):.1f} MB)'))

        # Create summary file
        summary_file = os.path.join(output_dir, 'export_summary.json')
        with open(summary_file, 'w', encoding='utf-8') as f:
            json.dump({
                'exported_at': timestamp,
                'total_records': total_exported,
                'apps_exported': list(models_by_app.keys()),
                'output_directory': output_dir,
                'compressed': do_compress,
                'zip_file': zip_filename if do_compress else None,
                'fixture_files': fixture_files
            }, f, indent=2)

        self.stdout.write(self.style.SUCCESS('\n' + '=' * 60))
        self.stdout.write(self.style.SUCCESS(f'EXPORT COMPLETE'))
        self.stdout.write(self.style.SUCCESS(f'Total records exported: {total_exported}'))
        self.stdout.write(self.style.SUCCESS(f'Output directory: {output_dir}'))
        if do_compress:
            self.stdout.write(self.style.SUCCESS(f'Compressed file: {zip_filename}'))
        self.stdout.write(self.style.SUCCESS(f'Summary file: {summary_file}'))
        self.stdout.write(self.style.SUCCESS('=' * 60))
        
        # Print import instructions
        self.stdout.write(self.style.SUCCESS('\n📥 TO IMPORT DATA:'))
        self.stdout.write(self.style.SUCCESS(f'   python manage.py loaddata {output_dir}/*/\\*_fixture.json'))
        self.stdout.write(self.style.SUCCESS('=' * 60))
