from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.views import APIView
from rest_framework import generics
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import status
from datetime import date, timedelta
from django.db.models import Sum, Count
from django.db.models.functions import TruncMonth
from .mpesa import MpesaClient
from .mpesa_handler import handle_stk_callback, handle_c2b_confirmation
from .models import Contribution, PaymentMethod, ContributionType
from .serializers import MpesaSTKPushSerializer
from .serializers import ContributionSerializer,ContributionTypeSerializer, PaymentMethodSerializer
from members.models import Member
import logging

logger = logging.getLogger(__name__)


class ContributionListCreateView(generics.ListCreateAPIView):
    serializer_class = ContributionSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        queryset = Contribution.objects.select_related(
            'member', 'contribution_type', 'payment_method'
        )
        member = self.request.query_params.get('member')
        c_type = self.request.query_params.get('type')
        start = self.request.query_params.get('start_date')
        end = self.request.query_params.get('end_date')
        status = self.request.query_params.get('status')

        if member:
            queryset = queryset.filter(member_id=member)
        if c_type:
            queryset = queryset.filter(contribution_type_id=c_type)
        if start:
            queryset = queryset.filter(date__gte=start)
        if end:
            queryset = queryset.filter(date__lte=end)
        if status:
            queryset = queryset.filter(status=status)
        return queryset


class ContributionDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Contribution.objects.select_related(
        'member', 'contribution_type', 'payment_method'
    )
    serializer_class = ContributionSerializer
    permission_classes = [permissions.IsAuthenticated]


class ContributionTypeListView(generics.ListCreateAPIView):
    queryset = ContributionType.objects.all()
    serializer_class = ContributionTypeSerializer
    permission_classes = [permissions.IsAuthenticated]

class ContributionTypeDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = ContributionType.objects.all()
    serializer_class = ContributionTypeSerializer
    permission_classes = [permissions.IsAuthenticated]    


class PaymentMethodListView(generics.ListCreateAPIView):
    queryset = PaymentMethod.objects.all()
    serializer_class = PaymentMethodSerializer
    permission_classes = [permissions.IsAuthenticated]

class PaymentMethodDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = PaymentMethod.objects.all()
    serializer_class = PaymentMethodSerializer
    permission_classes = [permissions.IsAuthenticated]
    
class FinanceSummaryView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        today = date.today()
        first_day = today.replace(day=1)
        last_month_end = first_day - timedelta(days=1)
        last_month_start = last_month_end.replace(day=1)

        total_all_time = Contribution.objects.filter(
            status='completed'
        ).aggregate(total=Sum('amount'))['total'] or 0

        this_month = Contribution.objects.filter(
            date__gte=first_day, status='completed'
        ).aggregate(total=Sum('amount'))['total'] or 0

        last_month = Contribution.objects.filter(
            date__gte=last_month_start,
            date__lte=last_month_end,
            status='completed'
        ).aggregate(total=Sum('amount'))['total'] or 0

        today_total = Contribution.objects.filter(
            date=today, status='completed'
        ).aggregate(total=Sum('amount'))['total'] or 0

        monthly_trend = Contribution.objects.filter(
            status='completed'
        ).annotate(
            month=TruncMonth('date')
        ).values('month').annotate(
            total=Sum('amount'),
            count=Count('id')
        ).order_by('month').values('month', 'total', 'count')

        return Response({
            'total_all_time': total_all_time,
            'this_month': this_month,
            'last_month': last_month,
            'today': today_total,
            'monthly_trend': list(monthly_trend),
        })


class STKPushView(APIView):
    """
    Called by both Next.js admin AND PHP public website.
    PHP posts: phone_number, amount, contribution_type_id, member_id
    """
    permission_classes = [AllowAny]

    def post(self, request):
        phone = request.data.get('phone_number', '')
        amount = request.data.get('amount', 0)
        member_id = request.data.get('member_id')
        contribution_type_id = request.data.get('contribution_type_id')
        account_ref = request.data.get('account_ref', 'Contribution')

        if not phone or not amount:
            return Response(
                {'error': 'Phone number and amount are required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Find member — optional for PHP public giving
        member = None
        if member_id:
            member = Member.objects.filter(id=member_id).first()
        if not member:
            member = Member.objects.filter(
                phone__endswith=str(phone)[-9:]
            ).first()

        # Get contribution type
        contribution_type = None
        if contribution_type_id:
            contribution_type = ContributionType.objects.filter(
                id=contribution_type_id
            ).first()
        if not contribution_type:
            contribution_type = ContributionType.objects.get_or_create(
                name='Offering'
            )[0]

        mpesa = MpesaClient()
        response = mpesa.stk_push(
            phone=phone,
            amount=amount,
            member_id=member.member_id if member else 'GUEST',
            contribution_type=contribution_type.name,
        )

        if response.get('ResponseCode') == '0':
            mpesa_method = PaymentMethod.objects.get_or_create(
                name='M-Pesa STK'
            )[0]
            contribution = Contribution.objects.create(
                member=member,
                amount=amount,
                contribution_type=contribution_type,
                payment_method=mpesa_method,
                source='STK',
                status='pending',
                phone_number=phone,
                checkout_request_id=response.get('CheckoutRequestID', ''),
                date=date.today(),
            )
            return Response({
                'success': True,
                'message': 'STK Push sent successfully',
                'checkout_request_id': response.get('CheckoutRequestID'),
                'contribution_id': contribution.id,
            })

        return Response(
            {
                'success': False,
                'error': 'Failed to initiate payment',
                'details': response
            },
            status=status.HTTP_400_BAD_REQUEST
        )


@api_view(['POST'])
@permission_classes([AllowAny])
def stk_callback(request):
    """Safaricom STK Push callback"""
    try:
        handle_stk_callback(request.data)
    except Exception as e:
        logger.error(f"STK callback error: {e}")
    return Response({"ResultCode": 0, "ResultDesc": "Accepted"})


@api_view(['POST'])
@permission_classes([AllowAny])
def c2b_confirmation(request):
    """Safaricom C2B Paybill confirmation"""
    try:
        handle_c2b_confirmation(request.data)
    except Exception as e:
        logger.error(f"C2B confirmation error: {e}")
    return Response({"ResultCode": 0, "ResultDesc": "Accepted"})


@api_view(['POST'])
@permission_classes([AllowAny])
def c2b_validation(request):
    """Safaricom C2B validation — always accept"""
    return Response({"ResultCode": 0, "ResultDesc": "Accepted"})