import logging
from django.core.management.base import BaseCommand, CommandError
from organization.models import SyncConfiguration, SyncLog
from organization.services.sync_service import OrganizationSyncService, SyncError

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    """
    Management command for syncing organizations from external API.
    
    Usage:
        python manage.py sync_organizations
        python manage.py sync_organizations --source default_source
        python manage.py sync_organizations --source default_source --max-records 100
        python manage.py sync_organizations --test-connection
        python manage.py sync_organizations --list-configs
    """

    help = "Sync organizations from external API"

    def add_arguments(self, parser):
        parser.add_argument(
            "--source",
            type=str,
            metavar="SOURCE_NAME",
            help="Sync configuration source name (uses default if not specified)"
        )
        parser.add_argument(
            "--max-records",
            type=int,
            metavar="MAX_RECORDS",
            help="Maximum organizations to sync (0 = all)"
        )
        parser.add_argument(
            "--test-connection",
            action="store_true",
            help="Test API connection without syncing"
        )
        parser.add_argument(
            "--list-configs",
            action="store_true",
            help="List all available sync configurations"
        )
        parser.add_argument(
            "--clear-cache",
            action="store_true",
            help="Clear API response cache before syncing"
        )
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Simulate sync without making changes (dry run)"
        )

    def handle(self, *args, **options):
        """Execute the command."""

        # List configurations
        if options["list_configs"]:
            return self._list_configurations()

        # Get sync configuration
        source_name = options.get("source")
        if source_name:
            try:
                config = SyncConfiguration.objects.get(source_name=source_name)
            except SyncConfiguration.DoesNotExist:
                raise CommandError(f"Sync configuration '{source_name}' not found")
        else:
            config = SyncConfiguration.objects.filter(is_active=True).first()
            if not config:
                raise CommandError(
                    "No active sync configuration found. "
                    "Use --list-configs to see available configurations."
                )

        if not config.is_active:
            raise CommandError(f"Sync configuration '{config.source_name}' is disabled")

        # Test connection
        if options["test_connection"]:
            return self._test_connection(config)

        # Clear cache
        if options["clear_cache"]:
            self._clear_cache(config)

        # Perform sync
        return self._sync_organizations(config, options)

    def _list_configurations(self):
        """List all available sync configurations."""
        configs = SyncConfiguration.objects.all()

        if not configs.exists():
            self.stdout.write(self.style.WARNING("No sync configurations found"))
            return

        self.stdout.write(self.style.HTTP_INFO("\n=== Sync Configurations ===\n"))

        for config in configs:
            status = "ACTIVE" if config.is_active else "DISABLED"
            status_style = self.style.SUCCESS if config.is_active else self.style.WARNING
            
            self.stdout.write(f"Name: {self.style.HTTP_INFO(config.source_name)}")
            self.stdout.write(f"Status: {status_style(status)}")
            self.stdout.write(f"URL: {config.base_url}{config.api_endpoint}")
            self.stdout.write(f"Auth Type: {config.auth_type}")
            self.stdout.write(f"Timeout: {config.timeout_seconds}s")
            self.stdout.write(f"Last Tested: {config.last_tested_at or 'Never'}")
            self.stdout.write("")

    def _test_connection(self, config):
        """Test connection to external API."""
        self.stdout.write(f"\nTesting connection to {config.source_name}...")

        try:
            success, message = config.test_connection()

            if success:
                self.stdout.write(
                    self.style.SUCCESS(f"✓ Connection successful: {message}")
                )
            else:
                self.stdout.write(
                    self.style.ERROR(f"✗ Connection failed: {message}")
                )
                raise CommandError("Connection test failed")

        except Exception as e:
            raise CommandError(f"Connection test error: {str(e)}")

    def _clear_cache(self, config):
        """Clear API cache."""
        self.stdout.write(f"\nClearing cache for {config.source_name}...")

        try:
            api_service = ExternalAPIService(config)
            api_service.clear_cache()
            self.stdout.write(self.style.SUCCESS("Cache cleared successfully"))
        except Exception as e:
            self.stdout.write(
                self.style.WARNING(f"Cache clearing failed: {str(e)}")
            )

    def _sync_organizations(self, config, options):
        """Perform the sync operation."""
        max_records = options.get("max_records")
        dry_run = options.get("dry_run", False)

        self.stdout.write(f"\n{'[DRY RUN] ' if dry_run else ''}")
        self.stdout.write(f"Starting sync for {self.style.HTTP_INFO(config.source_name)}...")

        if max_records:
            self.stdout.write(f"Limiting to {max_records} records")

        # Create sync log
        sync_log = SyncLog.objects.create(
            external_source=config.source_name,
            triggered_by="management_command",
            sync_type="partial" if max_records else "full"
        )

        try:
            # Initialize sync service
            sync_service = OrganizationSyncService(config)

            if dry_run:
                self.stdout.write(self.style.WARNING("(DRY RUN - Changes will not be saved)"))
                # In real implementation, would need to refactor service to support dry-run
                # For now, just test the API connection
                self.stdout.write("Testing API connection...")
                config.test_connection()
                self.stdout.write(self.style.SUCCESS("✓ API connection successful"))
                self.stdout.write(
                    self.style.WARNING(
                        "Note: Implement dry-run mode in OrganizationSyncService "
                        "for full functionality"
                    )
                )
                return

            # Perform sync
            sync_service.sync_organizations(sync_log, max_records=max_records)

            # Display results
            self._display_sync_results(sync_log)

        except SyncError as e:
            self.stdout.write(self.style.ERROR(f"✗ Sync failed: {str(e)}"))
            self.stdout.write(self.style.WARNING(f"Error details: {sync_log.error_message}"))
            raise CommandError(str(e))

        except Exception as e:
            self.stdout.write(self.style.ERROR(f"✗ Unexpected error: {str(e)}"))
            raise CommandError(str(e))

    def _display_sync_results(self, sync_log):
        """Display sync results in a formatted way."""
        self.stdout.write("\n" + "=" * 60)
        self.stdout.write(self.style.HTTP_SUCCESS("✓ SYNC COMPLETED"))
        self.stdout.write("=" * 60 + "\n")

        results_data = [
            ("Status", self._get_status_style(sync_log)),
            ("Duration", f"{sync_log.duration_seconds:.2f}s" if sync_log.duration_seconds else "N/A"),
            ("Total Fetched", sync_log.total_fetched),
            ("Created", self.style.SUCCESS(sync_log.created_count)),
            ("Updated", self.style.SUCCESS(sync_log.updated_count)),
            ("Skipped", sync_log.skipped_count),
            ("Errors", self.style.ERROR(sync_log.error_count) if sync_log.error_count > 0 else 0),
        ]

        for label, value in results_data:
            self.stdout.write(f"{label:.<20} {value}")

        if sync_log.error_message:
            self.stdout.write("\n" + self.style.WARNING("Error Details:"))
            self.stdout.write(sync_log.error_message)

        self.stdout.write("")

    def _get_status_style(self, sync_log):
        """Get colored status text."""
        if sync_log.is_successful:
            return self.style.SUCCESS(sync_log.status.upper())
        elif sync_log.status == SyncLog.SyncStatus.PARTIAL:
            return self.style.WARNING(sync_log.status.upper())
        else:
            return self.style.ERROR(sync_log.status.upper())
