# payments/api/views.py
from decimal import Decimal

from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
from django.db import transaction
from django.db.models import F

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
from rest_framework import status as http_status

from payments.models import ViralPeWallet, ViralPeWalletUsage
from payments.utils import generate_wallet_credit_order_id
from notifications.services import send_notification
from .serializers import WalletTopupSerializer

UserModel = get_user_model()  # runtime model (don't use for typing)


class WalletTopupAPI(APIView):
    """
    POST /api/wallet/topup/
    Requires auth + `payments.add_viralpewalletusage` permission.
    """
    permission_classes = [IsAuthenticated, DjangoModelPermissions]
    queryset = ViralPeWalletUsage.objects.all()  # needed for DjangoModelPermissions

    def post(self, request):
        s = WalletTopupSerializer(data=request.data)
        s.is_valid(raise_exception=True)
        data = s.validated_data

        # Use a concrete, always-available type for annotation
        target_user: AbstractBaseUser = data["target_user"]
        amount: Decimal = data["amount"]
        purpose_code: str = data["purpose_code"]
        purpose_note: str = data["purpose_note"]
        purpose_str: str = data["purpose_str"]

        final_purpose = purpose_str if not purpose_note else f"{purpose_str} | {purpose_note}"

        try:
            with transaction.atomic():
                wallet, _ = ViralPeWallet.objects.get_or_create(user=target_user)
                (ViralPeWallet.objects
                    .select_for_update()
                    .filter(pk=wallet.pk)
                    .update(balance=F('balance') + amount))
                wallet.refresh_from_db()

                order_id = generate_wallet_credit_order_id()

                usage = ViralPeWalletUsage.objects.create(
                    user=target_user,
                    amount_used=amount,
                    transaction_type='credit',
                    purpose=final_purpose,
                    purpose_code=purpose_code,    # ok if field exists
                    purpose_note=purpose_note,    # ok if field exists
                    order_id=order_id,
                    reference_user=request.user,
                )

            # Don’t fail the API if notifications hiccup
            try:
                send_notification(
                    user=target_user,
                    type_key="wallet_topup_credit",
                    context={
                        "user": target_user,
                        "amount": amount,
                        "order_id": usage.order_id,
                        "balance": wallet.balance,
                        "purpose": usage.purpose,
                    },
                    message=f"₹{amount} added to your ViralPe Wallet. Order {usage.order_id}.",
                )
            except Exception:
                pass

            return Response(
                {
                    "success": True,
                    "message": f"₹{amount} credited to {getattr(target_user, 'mobile_number', '')}.",
                    "order_id": usage.order_id,
                    "wallet": {
                        "user": getattr(target_user, 'mobile_number', None),
                        "balance": str(wallet.balance),
                    },
                    "usage": {
                        "id": usage.id,
                        "transaction_type": usage.transaction_type,
                        "amount": str(usage.amount_used),
                        "purpose": usage.purpose,
                        "purpose_code": getattr(usage, "purpose_code", None),
                        "created_at": usage.created_at,
                    },
                },
                status=http_status.HTTP_201_CREATED,
            )

        except Exception as e:
            return Response({"success": False, "error": str(e)}, status=http_status.HTTP_400_BAD_REQUEST)
