import re
from uuid import uuid4

from django.core.management.base import BaseCommand
from django.db import transaction
from django.utils import timezone

from apps.business.orders.models import Order
from apps.business.wallet.models import UserVoucherCode, WalletLedger


ORDER_REF_PATTERN = re.compile(r"^ORD-\d{10}-[A-Z0-9]{8}$")


def _build_reference(created_at):
    local_dt = timezone.localtime(created_at)
    return f"ORD-{local_dt:%y%m%d%H%M}-{uuid4().hex[:8].upper()}"


class Command(BaseCommand):
    help = "Backfill existing order reference IDs to ORD-YYMMDDHHMM-XXXXXXXX format."

    def add_arguments(self, parser):
        parser.add_argument(
            "--apply",
            action="store_true",
            help="Apply changes. Without this flag command runs as dry-run.",
        )

    def _generate_unique_reference(self, created_at):
        while True:
            new_ref = _build_reference(created_at)
            if Order.objects.filter(reference_id=new_ref).exists():
                continue
            if WalletLedger.objects.filter(reference_id__in=[new_ref, f"{new_ref}-VCH"]).exists():
                continue
            if UserVoucherCode.objects.filter(source_reference_id=f"{new_ref}-VCH").exists():
                continue
            return new_ref

    def handle(self, *args, **options):
        apply_changes = bool(options.get("apply"))

        stale_orders = list(
            Order.objects.exclude(reference_id__regex=r"^ORD-\d{10}-[A-Z0-9]{8}$").order_by("created_at")
        )

        if not stale_orders:
            self.stdout.write(self.style.SUCCESS("No order references need backfill."))
            return

        self.stdout.write(
            self.style.WARNING(
                f"Found {len(stale_orders)} orders with legacy reference IDs. "
                f"Mode: {'APPLY' if apply_changes else 'DRY-RUN'}"
            )
        )

        updated_orders = 0
        updated_ledgers = 0
        updated_vouchers = 0

        for order in stale_orders:
            old_ref = order.reference_id
            new_ref = self._generate_unique_reference(order.created_at)

            ledger_direct_count = WalletLedger.objects.filter(reference_id=old_ref).count()
            ledger_vch_count = WalletLedger.objects.filter(reference_id=f"{old_ref}-VCH").count()
            voucher_count = UserVoucherCode.objects.filter(source_reference_id=f"{old_ref}-VCH").count()

            self.stdout.write(
                f"Order {order.id}: {old_ref} -> {new_ref} "
                f"(ledger={ledger_direct_count + ledger_vch_count}, vouchers={voucher_count})"
            )

            if not apply_changes:
                continue

            with transaction.atomic():
                order.reference_id = new_ref
                order.save(update_fields=["reference_id"])

                if ledger_direct_count:
                    WalletLedger.objects.filter(reference_id=old_ref).update(reference_id=new_ref)

                if ledger_vch_count:
                    WalletLedger.objects.filter(reference_id=f"{old_ref}-VCH").update(reference_id=f"{new_ref}-VCH")

                if voucher_count:
                    UserVoucherCode.objects.filter(source_reference_id=f"{old_ref}-VCH").update(
                        source_reference_id=f"{new_ref}-VCH"
                    )

            updated_orders += 1
            updated_ledgers += ledger_direct_count + ledger_vch_count
            updated_vouchers += voucher_count

        if apply_changes:
            self.stdout.write(
                self.style.SUCCESS(
                    f"Backfill complete: orders={updated_orders}, ledgers={updated_ledgers}, vouchers={updated_vouchers}"
                )
            )
        else:
            self.stdout.write(
                self.style.WARNING(
                    "Dry-run complete. Re-run with --apply to persist changes."
                )
            )
