from rest_framework import status
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.accounts.models import User
from apps.common.permissions import IsAdmin

from . import services
from .models import Payout
from .serializers import PayoutRequestSerializer, PayoutSerializer
from .tasks import process_payout


class PayoutListCreateView(ListAPIView):
    """GET /payouts (admin, paginated) · POST /payouts (request a payout)."""

    serializer_class = PayoutSerializer

    def get_permissions(self):
        return [IsAdmin()] if self.request.method == 'GET' else [IsAuthenticated()]

    def get_queryset(self):
        qs = Payout.objects.select_related('user').all()
        params = self.request.query_params
        if params.get('status'):
            qs = qs.filter(status=params['status'])
        if params.get('search'):
            qs = qs.filter(user__name__icontains=params['search'])
        return qs.order_by('-created_at')

    def post(self, request):
        serializer = PayoutRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data

        # Resolve target seller (admins may act on behalf of a user).
        target = request.user
        if request.user.role == 'admin' and data.get('user_id'):
            target = User.objects.filter(pk=data['user_id']).first() or request.user

        idempotency_key = request.headers.get('Idempotency-Key')
        payout = services.request_payout(
            user=target,
            amount=data['amount'],
            payout_method=data['payout_method'],
            provider=data['provider'],
            account_name=data['account_name'],
            account_number=data.get('account_number', ''),
            idempotency_key=idempotency_key,
        )
        # Hand off the disbursement to the background worker. On hosts without a
        # Celery broker (e.g. shared cPanel), fall back to running it inline so
        # the payout still processes.
        try:
            process_payout.delay(payout.id)
        except Exception:
            process_payout(payout.id)
        return Response(
            {'id': payout.id, 'status': payout.status, 'message': 'Payout requested'},
            status=status.HTTP_201_CREATED)


class PayoutItemView(APIView):
    """
    Matches the existing PHP routing where `/payouts/<int>` is overloaded:
      * GET    treats the id as a **user id** (that seller's payout history)
      * PUT    treats the id as a **payout id** (admin sets paid/rejected)
      * DELETE treats the id as a **payout id** (admin removes a terminal payout)
    """

    def get_permissions(self):
        return [IsAdmin()] if self.request.method in ('PUT', 'DELETE') \
            else [IsAuthenticated()]

    def get(self, request, pk):
        if request.user.role != 'admin' and request.user.id != int(pk):
            return Response({'error': 'Forbidden'}, status=status.HTTP_403_FORBIDDEN)
        qs = Payout.objects.select_related('user').filter(user_id=pk).order_by('-created_at')
        return Response(PayoutSerializer(qs, many=True).data)

    def put(self, request, pk):
        payout = Payout.objects.filter(pk=pk).first()
        if not payout:
            return Response({'error': 'Payout not found'}, status=status.HTTP_404_NOT_FOUND)
        target = request.data.get('status')
        if target == Payout.Status.PAID:
            services.settle_payout(payout=payout, actor=request.user,
                                   provider_reference=request.data.get('reference', ''))
        elif target in (Payout.Status.REJECTED, Payout.Status.FAILED):
            services.reverse_payout(
                payout=payout, reason=request.data.get('reason', 'Rejected by admin'),
                final_status=Payout.Status.REJECTED, actor=request.user)
        else:
            return Response({'error': 'status must be paid or rejected'},
                            status=status.HTTP_400_BAD_REQUEST)
        return Response({'message': f'Payout {target}'})

    def delete(self, request, pk):
        payout = Payout.objects.filter(pk=pk).first()
        if not payout:
            return Response({'error': 'Payout not found'}, status=status.HTTP_404_NOT_FOUND)
        if not payout.is_terminal:
            return Response({'error': 'Only settled/failed payouts can be deleted'},
                            status=status.HTTP_400_BAD_REQUEST)
        payout.delete()
        return Response({'message': 'Payout deleted'})
