from datetime import datetime, time

from django.db import transaction
from django.utils import timezone
from rest_framework import status
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView

from Members.permissions import CanManageMembers

from .models import Attendance
from .serializers import AttendanceEventSerializer, AttendanceSerializer


class AttendanceEntryView(APIView):
    permission_classes = (AllowAny,)

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

        event_id = serializer.validated_data.get('event_id')
        if event_id:
            existing = (
                Attendance.objects.select_related('member')
                .filter(entry_event_id=event_id)
                .first()
            )
            if existing:
                return Response(AttendanceSerializer(existing).data)

        member = serializer.get_member()
        event_at = serializer.validated_data.get('event_at') or timezone.now()

        with transaction.atomic():
            open_attendance = (
                Attendance.objects
                .select_for_update()
                .filter(member=member, exit_at__isnull=True)
                .first()
            )

            if open_attendance:
                return Response(
                    {
                        'detail': 'این عضو در حال حاضر داخل باشگاه است.',
                        'attendance': AttendanceSerializer(open_attendance).data,
                    },
                    status=status.HTTP_409_CONFLICT,
                )

            attendance = Attendance.objects.create(
                member=member,
                entry_at=event_at,
                entry_event_id=event_id,
                entry_source=serializer.validated_data['source'],
                entry_device=serializer.validated_data['device'],
                notes=serializer.validated_data['notes'],
            )

        return Response(
            AttendanceSerializer(attendance).data,
            status=status.HTTP_201_CREATED,
        )


class AttendanceExitView(APIView):
    permission_classes = (AllowAny,)

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

        event_id = serializer.validated_data.get('event_id')
        if event_id:
            existing = (
                Attendance.objects.select_related('member')
                .filter(exit_event_id=event_id)
                .first()
            )
            if existing:
                return Response(AttendanceSerializer(existing).data)

        member = serializer.get_member()
        event_at = serializer.validated_data.get('event_at') or timezone.now()

        with transaction.atomic():
            attendance = (
                Attendance.objects
                .select_for_update()
                .filter(member=member, exit_at__isnull=True)
                .first()
            )

            if not attendance:
                return Response(
                    {'detail': 'برای این عضو ورود فعال وجود ندارد.'},
                    status=status.HTTP_409_CONFLICT,
                )

            attendance.exit_at = event_at
            attendance.exit_event_id = event_id
            attendance.exit_source = serializer.validated_data['source']
            attendance.exit_device = serializer.validated_data['device']
            if serializer.validated_data['notes']:
                attendance.notes = serializer.validated_data['notes']
            attendance.save(update_fields=('exit_at', 'exit_event_id', 'exit_source', 'exit_device', 'notes'))

        return Response(AttendanceSerializer(attendance).data)


class AttendanceCurrentView(APIView):
    permission_classes = (CanManageMembers,)

    def get(self, request):
        queryset = Attendance.objects.select_related('member').filter(exit_at__isnull=True)
        enroll_code = request.query_params.get('enroll_code')
        if enroll_code:
            queryset = queryset.filter(member__enroll_code=enroll_code)

        return Response(AttendanceSerializer(queryset, many=True).data)


class AttendanceHistoryView(APIView):
    permission_classes = (CanManageMembers,)

    def get(self, request):
        queryset = Attendance.objects.select_related('member').all()

        enroll_code = request.query_params.get('enroll_code')
        member_id = request.query_params.get('member_id')
        date_value = request.query_params.get('date')
        inside = request.query_params.get('inside')

        try:
            limit = min(max(int(request.query_params.get('limit', 100)), 1), 500)
        except (TypeError, ValueError):
            return Response(
                {'detail': 'limit باید یک عدد صحیح باشد.'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if enroll_code:
            queryset = queryset.filter(member__enroll_code=enroll_code)
        if member_id:
            queryset = queryset.filter(member_id=member_id)
        if inside == 'true':
            queryset = queryset.filter(exit_at__isnull=True)
        elif inside == 'false':
            queryset = queryset.filter(exit_at__isnull=False)
        if date_value:
            try:
                day = datetime.strptime(date_value, '%Y-%m-%d').date()
            except ValueError:
                return Response(
                    {'detail': 'فرمت date باید YYYY-MM-DD باشد.'},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            start = timezone.make_aware(datetime.combine(day, time.min))
            end = timezone.make_aware(datetime.combine(day, time.max))
            queryset = queryset.filter(entry_at__range=(start, end))

        return Response(AttendanceSerializer(queryset[:limit], many=True).data)
