import json
import logging

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

from django_devicehub.registry import registry
from django_devicehub.signals import device_provisioned

logger = logging.getLogger("django_devicehub")


class Command(BaseCommand):
    help = (
        "Bulk provision IoT devices with auto-generated credentials. "
        "Outputs credentials in JSON format for device onboarding."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            "device_type",
            help="Name of a registered DeviceType (e.g. 'weatherstation')",
        )
        parser.add_argument(
            "--count",
            type=int,
            default=1,
            help="Number of devices to create (default: 1)",
        )
        parser.add_argument(
            "--prefix",
            default="",
            help="Device ID prefix (default: '')",
        )
        parser.add_argument(
            "--output",
            default="",
            help="Write credentials to a JSON file (default: stdout)",
        )

    def handle(self, *args, **options):
        device_type_name = options["device_type"]
        count = options["count"]
        prefix = options["prefix"]
        output_file = options["output"]
        verbosity = options["verbosity"]

        # Look up the DeviceType
        dt_cls = registry.get(device_type_name)
        if dt_cls is None:
            available = ", ".join(dt.__name__ for dt in registry.all())
            raise CommandError(
                f"Unknown device type: '{device_type_name}'. "
                f"Registered types: {available or '(none)'}"
            )

        # Check that models exist
        if dt_cls._device_model is None:
            raise CommandError(
                f"DeviceType '{dt_cls.__name__}' has no models. "
                f"Call create_models() in your app's models.py."
            )

        if count < 1:
            raise CommandError("--count must be at least 1.")

        DeviceModel = dt_cls._device_model
        type_name = dt_cls.__name__.lower()

        # Determine starting index by checking existing device IDs
        existing_count = DeviceModel.objects.filter(
            device_id__startswith=f"{prefix}{type_name}-"
        ).count()
        start_index = existing_count + 1

        credentials_list = []
        created_count = 0

        for i in range(start_index, start_index + count):
            device_id = f"{prefix}{type_name}-{i:03d}"

            # Skip if device already exists
            if DeviceModel.objects.filter(device_id=device_id).exists():
                if verbosity >= 1:
                    self.stderr.write(
                        self.style.WARNING(f"  Skipped (exists): {device_id}")
                    )
                continue

            device = DeviceModel(
                device_id=device_id,
                name=f"{dt_cls.__name__} {i:03d}",
                status="provisioning",
                is_active=True,
            )

            # Generate credentials (returns plaintext, stores hashed)
            creds = device.generate_credentials()
            device.save()

            entry = {
                "device_id": device_id,
                "name": device.name,
                "device_type": dt_cls.__name__,
                **creds,
            }
            credentials_list.append(entry)
            created_count += 1

            # Fire signal
            device_provisioned.send(
                sender=dt_cls,
                device=device,
                credentials=creds,
            )

            if verbosity >= 2:
                self.stdout.write(self.style.SUCCESS(f"  Provisioned: {device_id}"))

        result = {
            "device_type": dt_cls.__name__,
            "count": created_count,
            "devices": credentials_list,
        }

        result_json = json.dumps(result, indent=2)

        if output_file:
            with open(output_file, "w") as f:
                f.write(result_json)
                f.write("\n")
            self.stdout.write(
                self.style.SUCCESS(
                    f"Provisioned {created_count} device(s). "
                    f"Credentials written to: {output_file}"
                )
            )
        else:
            self.stdout.write(result_json)

        if verbosity >= 1 and not output_file:
            self.stderr.write(
                self.style.WARNING(
                    "\nIMPORTANT: Credentials are shown in plaintext above. "
                    "Store them securely — passwords cannot be retrieved later."
                )
            )
