# views.py
from django.db import transaction
from django.utils import timezone
from django.views import View
from django.shortcuts import render
from django.http import JsonResponse, HttpRequest
from django.db.models import Q

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

def _norm(s):
    return (s or "").strip().lower()

def _as_bool(v) -> bool:
    if v is None:
        return False
    s = str(v).strip().lower()
    return s in {"1", "true", "yes", "y", "on"}

def run_sync_rps_from_rt(*, dry_run: bool, limit: int|None, verbose_list: bool, latest_first: bool):
    """
    Core logic: for each RPS (non-success), if there exists an RT Success for the same order_id,
    update RPS to Success (carry status_message where possible).
    Returns a dict with summary + optional change lines (for verbose).
    """
    order_by = "-id" if latest_first else "id"

    qs = RechargePaymentSummary.objects.all().order_by(order_by)
    qs = qs.exclude(recharge_status__iexact="Success")
    if limit:
        qs = qs[:limit]

    scanned = 0
    changed = 0
    no_order = 0
    changes_log = []

    ctx = transaction.atomic() if not dry_run else _NullContext()
    with ctx:
        # iterate in chunks for safety
        for rps in qs.iterator(chunk_size=500):
            scanned += 1
            order_id = getattr(rps, "order_id", None)
            if not order_id:
                no_order += 1
                continue

            # Prefer most recent RT success for the order
            rt_success = (
                RechargeTransaction.objects
                .filter(order_id=order_id, status__iexact="Success")
                .order_by("-created_at")
                .first()
            )
            if not rt_success:
                continue

            old_status = rps.recharge_status
            old_msg = getattr(rps, "status_message", "") or ""
            new_msg = getattr(rt_success, "status_message", None) or old_msg

            rps.recharge_status = "Success"
            try:
                rps.status_message = new_msg
            except Exception:
                pass

            if hasattr(rps, "updated_at"):
                try:
                    rps.updated_at = timezone.now()
                except Exception:
                    pass

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

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

    return {
        "scanned": scanned,
        "updated_to_success": changed,
        "skipped_no_order_id": no_order,
        "dry_run": dry_run,
        "latest_first": latest_first,
        "changes": changes_log if verbose_list else [],
    }

class _NullContext:
    def __enter__(self): return self
    def __exit__(self, exc_type, exc, tb): return False


class AdminSyncRPSView(View):
    template_name = "admin_tools/sync_rps_from_rt.html"

    def get(self, request):
        return render(request, self.template_name, {
            "result": None,
            "defaults": {
                "dry_run": True,          # default UI state only
                "verbose_list": False,
                "limit": "",
                "order": "desc",
            }
        })

    def post(self, request):
        # Because of the hidden inputs, we always receive "0" or "1"
        dry_run = _as_bool(request.POST.get("dry_run"))           # "1" -> True, "0" -> False
        verbose_list = _as_bool(request.POST.get("verbose_list")) # same
        try:
            limit = int(request.POST.get("limit") or 0) or None
        except Exception:
            limit = None
        order = (request.POST.get("order") or "desc").lower()
        latest_first = (order != "asc")

        result = run_sync_rps_from_rt(
            dry_run=dry_run,
            limit=limit,
            verbose_list=verbose_list,
            latest_first=latest_first,
        )

        return render(request, self.template_name, {
            "result": result,
            "defaults": {
                "dry_run": dry_run,
                "verbose_list": verbose_list,
                "limit": "" if limit is None else limit,
                "order": "desc" if latest_first else "asc",
            }
        })


class AdminSyncRPSJSON(View):
    """
    Optional JSON endpoint to trigger via AJAX or scripts:
    GET /devadmin/api/sync-rps/?dry_run=1&verbose=1&limit=200&order=desc
    """
    def get(self, request: HttpRequest):
        dry_run = _as_bool(request.GET.get("dry_run", "1"), True)
        verbose_list = _as_bool(request.GET.get("verbose", "0"), False)
        try:
            limit = int(request.GET.get("limit") or 0) or None
        except Exception:
            limit = None
        order = (request.GET.get("order") or "desc").lower()
        latest_first = (order != "asc")

        result = run_sync_rps_from_rt(
            dry_run=dry_run,
            limit=limit,
            verbose_list=verbose_list,
            latest_first=latest_first,
        )
        return JsonResponse(result, safe=False)



# views.py
from datetime import datetime
from django.db.models import OuterRef, Exists, Q
from django.shortcuts import render
from django.views import View
from django.core.paginator import Paginator
from django.utils.timezone import make_aware
from payments.models import PaymentTransaction
from recharge.models import RechargeTransaction
from payments.utils.razorpay_snap import fetch_razorpay_snapshot


def _parse_date(s: str, end=False):
    if not s:
        return None
    # Accept YYYY-MM-DD
    dt = datetime.strptime(s, "%Y-%m-%d")
    if end:
        # include whole day
        dt = dt.replace(hour=23, minute=59, second=59, microsecond=999999)
    return make_aware(dt)

STATUS_OPTIONS = [
    ("initiated", "Initiated"),
    ("verified", "Verified"),
    ("success", "Success"),
    ("failed", "Failed"),
    ("error", "Error"),
    ("cancelled", "Cancelled"),
    ("initiating", "Initiating"),
    ("notrequired", "NotRequired"),
]

# class AdminPaymentAuditView(View):
#     template_name = "admin_tools/payment_audit.html"

#     def get(self, request):
#         # Defaults: last 7 days, statuses 'initiated' and 'verified'
#         date_from = request.GET.get("date_from", "")
#         date_to   = request.GET.get("date_to", "")
#         statuses  = request.GET.getlist("status") or ["initiated", "verified"]
#         only_razorpay = request.GET.get("only_razorpay", "1")  # default ON
#         page      = int(request.GET.get("page", "1") or 1)
#         page_size = int(request.GET.get("page_size", "50") or 50)

#         dt_from = _parse_date(date_from) if date_from else None
#         dt_to   = _parse_date(date_to, end=True) if date_to else None

#         qs = PaymentTransaction.objects.all()

#         # Date filter
#         if dt_from:
#             qs = qs.filter(created_at__gte=dt_from)
#         if dt_to:
#             qs = qs.filter(created_at__lte=dt_to)

#         # Status filter
#         if statuses:
#             qs = qs.filter(status__in=statuses)

#         # Razorpay-involved (either order_id exists or gateway_amount>0)
#         if only_razorpay in {"1", "true", "on", "yes"}:
#             qs = qs.filter(Q(razorpay_order_id__isnull=False) | Q(gateway_amount__gt=0))

#         # Annotate existence of RT for same order_id
#         rt_subq = RechargeTransaction.objects.filter(order_id=OuterRef("order_id"))
#         qs = qs.annotate(has_rt=Exists(rt_subq))

#         # Order latest → old
#         qs = qs.order_by("-created_at")

#         paginator = Paginator(qs, page_size)
#         page_obj = paginator.get_page(page)

#         # Build rows with flags for the template
#         rows = []
#         for tx in page_obj.object_list:
#             is_verified   = (tx.status == "verified")
#             is_initiated  = (tx.status == "initiated")
#             has_rzp_oid   = bool(tx.razorpay_order_id)
#             has_rzp_pid   = bool(tx.razorpay_payment_id)
#             has_rt        = bool(getattr(tx, "has_rt", False))

#             # Suggested action logic
#             action = None
#             action_hint = None
#             action_href = None

#             if is_verified and not has_rt:
#                 action = "Investigate refund"
#                 action_hint = "Verified payment but no Recharge txn found."
#                 # link to your RPS/RT tools
#                 action_href = "/accounts/tools/sync-rps"  # adjust if different
#             elif is_initiated and not (has_rzp_oid and has_rzp_pid) and not has_rt:
#                 action = "Verify manually"
#                 action_hint = "Initiated without Razorpay IDs and no Recharge txn."
#                 # link to your inspector page to verify/check
#                 action_href = "/payments/inspect/"

#             rows.append({
#                 "tx": tx,
#                 "is_verified": is_verified,
#                 "is_initiated": is_initiated,
#                 "has_rzp_oid": has_rzp_oid,
#                 "has_rzp_pid": has_rzp_pid,
#                 "has_rt": has_rt,
#                 "action": action,
#                 "action_hint": action_hint,
#                 "action_href": action_href,
#             })

#         context = {
#             "filters": {
#                 "date_from": date_from,
#                 "date_to": date_to,
#                 "statuses": statuses,
#                 "only_razorpay": only_razorpay in {"1", "true", "on", "yes"},
#                 "page_size": page_size,
#             },
#             "status_options": STATUS_OPTIONS,
#             "page_obj": page_obj,
#             "rows": rows,
#         }
#         return render(request, self.template_name, context)


# views.py (append to the previous implementation)


class AdminPaymentAuditView(View):
    template_name = "admin_tools/payment_audit.html"

    def get(self, request):
        # existing filters...
        date_from = request.GET.get("date_from", "")
        date_to   = request.GET.get("date_to", "")
        statuses  = request.GET.getlist("status") or ["initiated", "verified"]
        only_razorpay = request.GET.get("only_razorpay", "1")
        page      = int(request.GET.get("page", "1") or 1)
        page_size = int(request.GET.get("page_size", "50") or 50)
        load_rzp  = request.GET.get("load_rzp", "0") in {"1","true","on","yes"}  # NEW

        dt_from = _parse_date(date_from) if date_from else None
        dt_to   = _parse_date(date_to, end=True) if date_to else None

        qs = PaymentTransaction.objects.all()
        if dt_from: qs = qs.filter(created_at__gte=dt_from)
        if dt_to:   qs = qs.filter(created_at__lte=dt_to)
        if statuses: qs = qs.filter(status__in=statuses)
        if only_razorpay in {"1", "true", "on", "yes"}:
            qs = qs.filter(Q(razorpay_order_id__isnull=False) | Q(gateway_amount__gt=0))

        rt_subq = RechargeTransaction.objects.filter(order_id=OuterRef("order_id"))
        qs = qs.annotate(has_rt=Exists(rt_subq)).order_by("-created_at")

        paginator = Paginator(qs, page_size)
        page_obj = paginator.get_page(page)

        rows = []
        # (Optional) small guard: don’t hammer RZP if page_size is gigantic
        do_rzp = load_rzp and page_obj.object_list

        for tx in page_obj.object_list:
            is_verified   = (tx.status == "verified")
            is_initiated  = (tx.status == "initiated")
            has_rzp_oid   = bool(tx.razorpay_order_id)
            has_rzp_pid   = bool(tx.razorpay_payment_id)
            has_rt        = bool(getattr(tx, "has_rt", False))

            # Prepare RZP snapshot (only when needed and requested)
            rzp = None
            if do_rzp and has_rzp_oid and not has_rt and (is_verified or is_initiated):
                rzp = fetch_razorpay_snapshot(tx.razorpay_order_id)

            # Decide action with RZP data (if fetched)
            action = None
            action_hint = None
            action_href = None

            if rzp and rzp.get("ok"):
                r_order = rzp.get("order") or {}
                r_pay   = rzp.get("latest_payment") or {}
                order_status = (r_order.get("status") or "").lower()    # 'paid', 'created', etc.
                pay_status   = (r_pay.get("status") or "").lower()      # 'captured', 'authorized', etc.
                pay_amt      = r_pay.get("amount")
                pay_curr     = r_pay.get("currency")
                # amount match in paise
                expected_amt = int(round(float(tx.amount) * 100))

                # Refund suggestion rule:
                # captured + INR + amount==expected + NO RT
                if (order_status == "paid" and
                    pay_status == "captured" and
                    pay_curr == "INR" and
                    pay_amt == expected_amt and
                    not has_rt):
                    action = "Process refund"
                    action_hint = "Captured payment without Recharge txn."
                    # Link to your refund page / API
                    action_href = "/accounts/tools/refund"  # adjust to your AdminRefund page/endpoint

            # Fallback actions (same as earlier if no RZP or not ok)
            if not action:
                if is_verified and not has_rt:
                    action = "Investigate refund"
                    action_hint = "Verified payment but no Recharge txn found."
                    action_href = "/accounts/tools/sync-rps"
                elif is_initiated and not (has_rzp_oid and has_rzp_pid) and not has_rt:
                    action = "Verify manually"
                    action_hint = "Initiated without Razorpay IDs and no Recharge txn."
                    action_href = "/payments/inspect/"

            rows.append({
                "tx": tx,
                "is_verified": is_verified,
                "is_initiated": is_initiated,
                "has_rzp_oid": has_rzp_oid,
                "has_rzp_pid": has_rzp_pid,
                "has_rt": has_rt,
                "rzp": rzp,  # snapshot (or None)
                "action": action,
                "action_hint": action_hint,
                "action_href": action_href,
            })

        context = {
            "filters": {
                "date_from": date_from,
                "date_to": date_to,
                "statuses": statuses,
                "only_razorpay": only_razorpay in {"1", "true", "on", "yes"},
                "page_size": page_size,
                "load_rzp": load_rzp,  # NEW
            },
            "status_options": STATUS_OPTIONS,
            "page_obj": page_obj,
            "rows": rows,
        }
        return render(request, self.template_name, context)
