from rest_framework import viewsets, status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAdminUser, AllowAny

from apps.attendance.models import RegisteredMember
from .models import MotionEvent, MotionVote
from .serializers import MotionEventSerializer, MotionVoteSerializer


def _get_client_ip(request):
    xff = request.META.get('HTTP_X_FORWARDED_FOR')
    return xff.split(',')[0].strip() if xff else request.META.get('REMOTE_ADDR', 'unknown')


def _stats(event):
    yes = event.yes_count
    no = event.no_count
    total = yes + no
    return {
        'yes_count': yes,
        'no_count': no,
        'total_votes': total,
        'yes_pct': round(yes / total * 100, 1) if total else 0,
        'no_pct': round(no / total * 100, 1) if total else 0,
    }


class MotionEventViewSet(viewsets.ModelViewSet):
    queryset = MotionEvent.objects.all()
    serializer_class = MotionEventSerializer
    permission_classes = [IsAdminUser]


class PublicActiveMotionView(APIView):
    """Returns the currently active motion with live vote counts."""
    permission_classes = [AllowAny]

    def get(self, request):
        event = MotionEvent.objects.filter(is_active=True, is_archived=False).first()
        if not event:
            return Response({'detail': 'No active motion.'}, status=status.HTTP_404_NOT_FOUND)
        return Response({
            'id': event.id,
            'name': event.name,
            'slug': event.slug,
            'description': event.description,
            **_stats(event),
        })


class PublicMotionVoteView(APIView):
    """
    Public voting endpoint.
    - Verifies the registration code against RegisteredMember.
    - One vote per member per motion (idempotent: returns existing vote if already cast).
    - Returns updated live stats on every response.
    """
    permission_classes = [AllowAny]

    def post(self, request):
        registration_code = (request.data.get('registration_code') or '').strip().upper()
        event_id = request.data.get('event_id')
        vote = (request.data.get('vote') or '').strip().upper()

        if not registration_code or not event_id:
            return Response(
                {'success': False, 'message': 'Registration code and event are required.'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if vote not in ('YES', 'NO'):
            return Response(
                {'success': False, 'message': 'Vote must be YES or NO.'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            event = MotionEvent.objects.get(id=event_id, is_active=True, is_archived=False)
        except MotionEvent.DoesNotExist:
            return Response(
                {'success': False, 'message': 'Voting is not currently open.'},
                status=status.HTTP_404_NOT_FOUND,
            )

        try:
            member = RegisteredMember.objects.get(registration_code__iexact=registration_code)
        except RegisteredMember.DoesNotExist:
            return Response(
                {'success': False, 'message': 'Registration code not found. Please check your code and try again.', 'code': 'NOT_FOUND'},
                status=status.HTTP_404_NOT_FOUND,
            )

        existing = MotionVote.objects.filter(event=event, registration_code=registration_code).first()
        if existing:
            return Response({
                'success': True,
                'already_voted': True,
                'full_name': existing.full_name or registration_code,
                'vote': existing.vote,
                'message': f'You have already voted {existing.vote} on this motion.',
                **_stats(event),
            })

        MotionVote.objects.create(
            event=event,
            registration_code=registration_code,
            full_name=member.full_name,
            vote=vote,
            ip_address=_get_client_ip(request),
        )

        return Response({
            'success': True,
            'already_voted': False,
            'full_name': member.full_name,
            'vote': vote,
            'message': f'Your vote ({vote}) has been recorded. Thank you!',
            **_stats(event),
        }, status=status.HTTP_201_CREATED)


class PublicMotionCheckView(APIView):
    """
    Pre-vote check: verifies the registration code and returns whether
    the member has already voted — without casting a vote.
    """
    permission_classes = [AllowAny]

    def post(self, request):
        registration_code = (request.data.get('registration_code') or '').strip().upper()
        event_id = request.data.get('event_id')

        if not registration_code or not event_id:
            return Response(
                {'success': False, 'message': 'Registration code and event are required.'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            event = MotionEvent.objects.get(id=event_id, is_active=True, is_archived=False)
        except MotionEvent.DoesNotExist:
            return Response(
                {'success': False, 'message': 'Voting is not currently open.'},
                status=status.HTTP_404_NOT_FOUND,
            )

        try:
            member = RegisteredMember.objects.get(registration_code__iexact=registration_code)
        except RegisteredMember.DoesNotExist:
            return Response(
                {'success': False, 'message': 'Registration code not found. Please check your code and try again.', 'code': 'NOT_FOUND'},
                status=status.HTTP_404_NOT_FOUND,
            )

        existing = MotionVote.objects.filter(event=event, registration_code=registration_code).first()
        return Response({
            'success': True,
            'full_name': member.full_name,
            'already_voted': bool(existing),
            'vote': existing.vote if existing else None,
            **(_stats(event) if existing else {}),
        })


class PublicMotionStatsView(APIView):
    """Lightweight polling endpoint — returns only live vote stats."""
    permission_classes = [AllowAny]

    def get(self, request):
        event_id = request.query_params.get('event_id')
        try:
            event = MotionEvent.objects.get(id=event_id) if event_id else MotionEvent.objects.filter(is_active=True, is_archived=False).first()
            if not event:
                raise MotionEvent.DoesNotExist
        except MotionEvent.DoesNotExist:
            return Response({'detail': 'No active motion.'}, status=status.HTTP_404_NOT_FOUND)
        return Response(_stats(event))


class MotionVotesView(APIView):
    """Admin — list all votes for a given motion event."""
    permission_classes = [IsAdminUser]

    def get(self, request):
        event_id = request.query_params.get('event_id')
        if event_id:
            votes = MotionVote.objects.filter(event_id=event_id).order_by('-voted_at')
        else:
            event = MotionEvent.objects.filter(is_active=True, is_archived=False).first()
            votes = MotionVote.objects.filter(event=event).order_by('-voted_at') if event else MotionVote.objects.none()
        return Response(MotionVoteSerializer(votes, many=True).data)
