"""
Management command: backfill_referral_codes

Usage:
    python manage.py backfill_referral_codes
    python manage.py backfill_referral_codes --set-referred-by 8096248999 --referrer 8668192080
    python manage.py backfill_referral_codes --set-referred-by 8096248999 --referrer 8668192080 --force

Options:
    --set-referred-by MOBILE   Mobile of the user whose referred_by should be set/updated.
    --referrer MOBILE          Mobile of the user who is the referrer.
    --force                    Override an already-set referred_by relationship.
"""
import uuid

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction


class Command(BaseCommand):
    help = "Generate referral codes for all users who don't have one, and optionally wire referred_by."

    def add_arguments(self, parser):
        parser.add_argument(
            "--set-referred-by",
            metavar="MOBILE",
            help="Mobile number of the user to set referred_by for.",
        )
        parser.add_argument(
            "--referrer",
            metavar="MOBILE",
            help="Mobile number of the referrer.",
        )
        parser.add_argument(
            "--force",
            action="store_true",
            default=False,
            help="Force override even if referred_by is already set.",
        )

    def _unique_code(self, model):
        for _ in range(10):
            candidate = str(uuid.uuid4())[:10].replace("-", "").upper()
            if not model.objects.filter(referral_code=candidate).exists():
                return candidate
        raise CommandError("Could not generate a unique referral code after 10 attempts.")

    def handle(self, *args, **options):
        from apps.accounts.models import User

        # ── 1. Backfill referral codes for users who don't have one ──────────
        missing_qs = User.objects.filter(referral_code__isnull=True) | User.objects.filter(referral_code="")
        missing = list(missing_qs.distinct())

        if missing:
            self.stdout.write(f"Found {len(missing)} user(s) without a referral code. Generating…")
            updated = 0
            for user in missing:
                code = self._unique_code(User)
                user.referral_code = code
                user.save(update_fields=["referral_code"])
                updated += 1
                self.stdout.write(f"  ✓ {user.mobile or user.email} → {code}")
            self.stdout.write(self.style.SUCCESS(f"Backfilled {updated} referral code(s)."))
        else:
            self.stdout.write("All users already have referral codes.")

        # ── 2. Optionally wire referred_by ────────────────────────────────────
        target_mobile = options.get("set_referred_by")
        referrer_mobile = options.get("referrer")

        if target_mobile or referrer_mobile:
            if not target_mobile or not referrer_mobile:
                raise CommandError("Both --set-referred-by and --referrer must be provided together.")

            try:
                target = User.objects.get(mobile=target_mobile)
            except User.DoesNotExist:
                raise CommandError(f"User with mobile '{target_mobile}' not found.")

            try:
                referrer = User.objects.get(mobile=referrer_mobile)
            except User.DoesNotExist:
                raise CommandError(f"Referrer with mobile '{referrer_mobile}' not found.")

            if target.pk == referrer.pk:
                raise CommandError("A user cannot refer themselves.")

            if target.referred_by_id and not options["force"]:
                current = target.referred_by
                self.stdout.write(
                    self.style.WARNING(
                        f"User {target_mobile} is already referred by "
                        f"{getattr(current, 'mobile', None) or getattr(current, 'email', None)} "
                        f"(id={current.pk}). Use --force to override."
                    )
                )
                return

            with transaction.atomic():
                target.referred_by = referrer
                target.save(update_fields=["referred_by"])

            action = "Updated" if target.referred_by_id else "Set"
            self.stdout.write(
                self.style.SUCCESS(
                    f"{action} referred_by: {target_mobile} is now referred by "
                    f"{referrer_mobile} (referral_code={referrer.referral_code})."
                )
            )
