# payments/management/commands/sync_rps_from_rt.py
from django.core.management.base import BaseCommand
from django.db import transaction
from django.utils import timezone

from payments.models import RechargePaymentSummary
from recharge.models import RechargeTransaction


SUCCESS_VALUES = {"success", "succeeded", "ok"}
PENDING_VALUES = {"pending", "init", "initiated", "inprogress", "in_progress"}
FAILURE_VALUES = {"failed", "failure", "error"}

def norm(s: str | None) -> str:
    return (s or "").strip().lower()

class Command(BaseCommand):
    help = (
        "For each RechargePaymentSummary: if the matching RechargeTransaction "
        "status is Success and summary is Pending/Failure, mark summary Success."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Show what would change without saving anything.",
        )
        parser.add_argument(
            "--limit",
            type=int,
            default=None,
            help="Optional limit on number of summaries to scan (for testing).",
        )
        parser.add_argument(
            "--verbose-list",
            action="store_true",
            help="Print each changed order_id and old/new values.",
        )

    def handle(self, *args, **options):
        dry_run: bool = options["dry_run"]
        limit: int | None = options["limit"]
        verbose_list: bool = options["verbose_list"]

        qs = RechargePaymentSummary.objects.all().order_by("id")

        # Only scan RPS that aren't already success
        qs = qs.exclude(recharge_status__iexact="Success")
        # Optional limit
        if limit:
            qs = qs[:limit]

        scanned = 0
        changed = 0
        no_match = 0
        already_ok = 0

        # For nicer output grouping
        changes_log = []

        # Wrap writes in a single atomic transaction (no-op if dry-run)
        ctx = transaction.atomic() if not dry_run else _NullContext()

        with ctx:
            for rps in qs.iterator(chunk_size=1000):
                scanned += 1

                order_id = getattr(rps, "order_id", None)
                if not order_id:
                    no_match += 1
                    continue

                # Find a success RT for this order_id (prefer most recently updated)
                rt_qs = RechargeTransaction.objects.filter(order_id=order_id)
                rt_success = (
                    rt_qs.filter(status__iexact="Success")
                    .order_by("-created_at")
                    .first()
                )

                if not rt_success:
                    # No success transaction found for this order
                    # (Could be pending/failed or missing altogether)
                    continue

                # rps is not marked success (we excluded above), so it’s either pending or failure
                old_status = rps.recharge_status
                old_msg = getattr(rps, "status_message", "")

                # Update fields
                rps.recharge_status = "Success"
                # If you want to carry over provider message, use rt_success.status_message when present
                new_msg = getattr(rt_success, "status_message", None) or old_msg
                try:
                    setattr(rps, "status_message", new_msg)
                except Exception:
                    pass  # status_message may not exist or be read-only; ignore

                # Touch updated_at if model doesn’t auto_now
                if hasattr(rps, "updated_at"):
                    try:
                        rps.updated_at = timezone.now()
                    except Exception:
                        pass

                changed += 1
                if verbose_list:
                    changes_log.append(
                        f"{order_id}: {old_status!r} -> 'Success' "
                        f"(msg: {old_msg!r} -> {new_msg!r})"
                    )

                if not dry_run:
                    rps.save(update_fields=["recharge_status", "status_message", "updated_at"]
                             if hasattr(rps, "updated_at")
                             else ["recharge_status", "status_message"])

        # Output summary
        self.stdout.write(self.style.MIGRATE_HEADING("RechargePaymentSummary sync report"))
        self.stdout.write(f"Scanned: {scanned}")
        self.stdout.write(f"Updated to Success: {changed}")
        self.stdout.write(f"No order_id / not processable: {no_match}")
        self.stdout.write(f"Already Success (excluded from scan): {already_ok}")
        self.stdout.write(f"Dry-run: {dry_run}")

        if verbose_list and changes_log:
            self.stdout.write(self.style.HTTP_INFO("\nChanges:"))
            for line in changes_log:
                self.stdout.write(f" - {line}")


class _NullContext:
    """No-op context manager so we can reuse the same code path for dry-run."""
    def __enter__(self): return self
    def __exit__(self, exc_type, exc, tb): return False




# # Preview what would change (no writes)
# python manage.py sync_rps_from_rt --dry-run --verbose-list --limit 200

# # Do the actual updates
# python manage.py sync_rps_from_rt

# # Update but print the per-order changes for auditing
# python manage.py sync_rps_from_rt --verbose-list
