'''
Seed command


This management command seeds Django models with synthetic data using a configurable
mapping system. It supports JSON/YAML configuration files, direct model targeting,
data clearing, dry-run previews, and relational data seeding.
'''



from django.core.management.base import BaseCommand, CommandError
from django.apps import apps 
from django_seeder import BulkModelLoader, ConfigParser


class Command(BaseCommand):
    
    help = 'Seed Django models with synthetic data'
    
    def add_arguments(self, parser):
        parser.add_argument(
            '--config',
            type=str,
            default=None,
            help='Path to seed configuration file (JSON or YAML)'
        )
        parser.add_argument(
            '--model',
            type=str,
            default=None,
            help='Seed specific model (format: app_label.ModelName)'
        )
        parser.add_argument(
            '--rows',
            type=int,
            default=10,
            help='Number of rows to seed (default: 10)'
        )
        parser.add_argument(
            '--app',
            type=str,
            default=None,
            help='Django app label name'
        )
        parser.add_argument(
            '--clear',
            action='store_true',
            help='Clear existing data in models before seeding'
        )
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Show what would be seeded without actually seeding'
        )
        parser.add_argument(
            '--verbose',
            action='store_true',
            help='Show detailed output'
        )
        
    def handle(self, *args, **options):
        loader = BulkModelLoader()
        config = None 
        
        if options['config']:
            try:
                config = ConfigParser.load_config(options['config'])
                
                if not ConfigParser.validate_config(config):
                    raise CommandError('Invalid file configuration format')
                
                for model_name in config.keys():
                    try:
                        app_label = config[model_name].get('app_label', 'core')
                        model = apps.get_model(app_label, model_name)
                        loader.register(model)
                    except LookupError:
                        raise CommandError(f'Model not found: {app_label}.{model_name}')
                
                self.stdout.write(
                    self.style.SUCCESS(f'Loaded config from {options["config"]}')
                )
            except FileNotFoundError:
                raise CommandError(f'Configuration file not found: {options["config"]}')
            except Exception as e:
                raise CommandError(f'Error loading config: {str(e)}')
            
        elif options['model'] and options['app']:
            app_label = options['app']
            model_name = options['model']
            rows = options['rows']
            
            try:
                model = apps.get_model(app_label, model_name) 
                loader.register(model)
                
                config = {
                    model_name: {
                        'rows': rows,
                        'mapping': self._get_default_mapping(model)
                    }
                }
                
                self.stdout.write(
                    self.style.WARNING(
                        f'No mapping provided. Using auto-detected fields for {model_name}'
                    )
                )
            except LookupError:
                raise CommandError(f'Model not found: {app_label}.{model_name}')
            
        else:
            raise CommandError('Either --config or both --model and --app must be provided')
        
        if not config:
            raise CommandError('No configuration available')
        
        if options['clear']:
            self.stdout.write(
                self.style.WARNING('Clearing existing data...')
            )
            
            for model_name in loader.seeders:
                loader.clear(model_name)
            
            self.stdout.write(
                self.style.SUCCESS('Data successfully cleared')
            )
        
        if options['dry_run']:
            self.stdout.write(
                self.style.WARNING('DRY RUN MODE')
            )
            
            for model_name, model_config in config.items():
                rows = model_config.get('rows', 10)
                
                self.stdout.write(
                    f'  Would seed {rows} rows in {model_name}'
                )
            return 
        
        try:
            results = {}
            
            for model_name, model_config in config.items():
                seeder = loader.seeders[model_name]
                rows = model_config.get('rows', 10)
                mapping = model_config.get('mapping', {})
                relations = model_config.get('relations', {})
                
                if relations:
                    relation_resolvers = {}
                    for rel_field, rel_model_name in relations.items():
                        if rel_model_name in results:
                            instances = results[rel_model_name]
                            relation_resolvers[rel_field] = lambda: instances[__import__('random').randint(0, len(instances) - 1)]
                    
                    result = seeder.seed_with_relations(rows, mapping, relation_resolvers)
                else:
                    result = seeder.seed(rows, mapping)
                
                results[model_name] = result
            
            self.stdout.write(
                self.style.SUCCESS('Seeding successfully completed')
            )
            
            for model_name, instances in results.items():
                self.stdout.write(
                    f'{model_name}: {len(instances)} rows seeded'
                )
            
            if options['verbose']:
                self.stdout.write('\nDetailed Results')
                
                for model_name, instances in results.items():
                    self.stdout.write(f'\n{model_name}')
                    
                    for index, instance in enumerate(instances[:3], 1):
                        self.stdout.write(f' {index}. {instance}')
                    
                    if len(instances) > 3:
                        self.stdout.write(f' ... and {len(instances) - 3} more')
        
        except Exception as e:
            raise CommandError(f'Error during seeding: {str(e)}')
    
    def _get_default_mapping(self, model):
        mapping = {}
        for field in model._meta.get_fields():
            if field.many_to_one or field.one_to_one or field.many_to_many or field.primary_key:
                continue
            mapping[field.name] = field.name
        return mapping