import csv
import io
import math
from django.core.cache import cache
from django.db.models import Count
from django.utils import timezone
from rest_framework import viewsets, status, generics
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny
from rest_framework.parsers import MultiPartParser, FormParser

from .models import RegisteredMember, AttendanceRecord, ScannerAssignment
from .serializers import (
    RegisteredMemberSerializer, AttendanceRecordSerializer,
    ScannerAssignmentSerializer, ScanBarcodeSerializer, CSVUploadSerializer,
)
from apps.events.models import Event


def _haversine_m(lat1, lng1, lat2, lng2):
    """Return distance in metres between two GPS points."""
    R = 6_371_000
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp = math.radians(lat2 - lat1)
    dl = math.radians(lng2 - lng1)
    a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
    return R * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))


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')


# Default venue: Avani Victoria Falls Resort, Mosi-oa-Tunya Road, Livingstone, Zambia
DEFAULT_VENUE_LAT = -17.9243
DEFAULT_VENUE_LNG = 25.8657


class PublicActiveCheckInEventView(APIView):
    """Returns all events currently open for self-check-in."""
    permission_classes = [AllowAny]

    def get(self, request):
        events = Event.objects.filter(
            self_checkin_enabled=True, is_active=True, is_archived=False
        ).select_related('category')
        data = [
            {
                'id': e.id,
                'name': e.name,
                'event_type': e.event_type,
                'location': e.location,
                'category_name': e.category.name if e.category else '',
                'radius_m': e.self_checkin_radius_m,
            }
            for e in events
        ]
        return Response(data)


class PublicSelfCheckInView(APIView):
    """
    Public self-check-in with:
      - Geofence validation (GPS must be within radius of venue)
      - IP rate limiting (max 5 per IP per 10 minutes)
      - Package / category validation
      - One-time check-in per member per event
    """
    permission_classes = [AllowAny]

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

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

        # ── Rate limiting ────────────────────────────────────────────────────
        ip = _get_client_ip(request)
        rate_key = f'self_checkin_rate_{ip}'
        attempts = cache.get(rate_key, 0)
        if attempts >= 5:
            return Response(
                {'success': False, 'message': 'Too many check-in attempts. Please wait a few minutes before trying again.', 'code': 'RATE_LIMITED'},
                status=status.HTTP_429_TOO_MANY_REQUESTS,
            )
        cache.set(rate_key, attempts + 1, 600)  # 10-minute window

        # ── Event lookup ─────────────────────────────────────────────────────
        try:
            event = Event.objects.select_related('category').get(
                id=event_id, self_checkin_enabled=True, is_active=True, is_archived=False
            )
        except Event.DoesNotExist:
            return Response(
                {'success': False, 'message': 'Self check-in is not currently available for this event.', 'code': 'EVENT_UNAVAILABLE'},
                status=status.HTTP_404_NOT_FOUND,
            )

        # ── Geofence ─────────────────────────────────────────────────────────
        if latitude is None or longitude is None:
            return Response(
                {'success': False, 'message': 'Your location is required. Please enable GPS/location access and try again.', 'code': 'GPS_REQUIRED'},
                status=status.HTTP_400_BAD_REQUEST,
            )
        try:
            lat, lng = float(latitude), float(longitude)
        except (ValueError, TypeError):
            return Response(
                {'success': False, 'message': 'Invalid GPS coordinates.', 'code': 'GPS_INVALID'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        venue_lat = float(event.self_checkin_lat) if event.self_checkin_lat else DEFAULT_VENUE_LAT
        venue_lng = float(event.self_checkin_lng) if event.self_checkin_lng else DEFAULT_VENUE_LNG
        radius = event.self_checkin_radius_m or 500
        distance = int(_haversine_m(lat, lng, venue_lat, venue_lng))

        if distance > radius:
            return Response(
                {
                    'success': False,
                    'code': 'OUT_OF_RANGE',
                    'distance_m': distance,
                    'message': (
                        f'You must be at the event venue to self check-in. '
                        f'You appear to be {distance}m away (maximum allowed: {radius}m). '
                        f'Please move closer to the venue.'
                    ),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # ── Member lookup ─────────────────────────────────────────────────────
        try:
            member = RegisteredMember.objects.select_related('event_category').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,
            )

        # ── Category check ────────────────────────────────────────────────────
        if member.event_category and event.category:
            if member.event_category != event.category:
                return Response({
                    'success': False,
                    'code': 'CATEGORY_MISMATCH',
                    'message': (
                        f'You are registered under "{member.event_category.name}" but this event belongs to '
                        f'"{event.category.name}". Please check with the registration desk.'
                    ),
                })

        # ── Package check ─────────────────────────────────────────────────────
        if event.event_type and event.event_type != 'ALL':
            pkg_upper = (member.package_name or '').upper()
            if event.event_type.upper() not in pkg_upper:
                return Response({
                    'success': False,
                    'code': 'PACKAGE_MISMATCH',
                    'message': (
                        f'Your package "{member.package_name or "N/A"}" does not include access to '
                        f'{event.event_type.title()}. '
                        f'Please visit the registration desk if you believe this is an error.'
                    ),
                    'package_name': member.package_name or 'N/A',
                    'event_type': event.event_type,
                })

        # ── Already checked in? ───────────────────────────────────────────────
        existing = AttendanceRecord.objects.filter(
            member=member, event=event, scan_type='CHECK_IN'
        ).first()
        if existing:
            return Response({
                'success': True,
                'already_checked_in': True,
                'member_name': member.full_name,
                'check_in_time': existing.scan_time,
                'message': f'You have already checked in at {existing.scan_time.strftime("%H:%M on %d %b %Y")}.',
            })

        # ── Record check-in ───────────────────────────────────────────────────
        record = AttendanceRecord.objects.create(
            member=member,
            event=event,
            scan_type='CHECK_IN',
            scan_time=timezone.now(),
            recorded_by=None,
        )
        return Response({
            'success': True,
            'already_checked_in': False,
            'member_name': member.full_name,
            'package_name': member.package_name or '',
            'check_in_time': record.scan_time,
            'message': f'Welcome, {member.full_name}! Your attendance has been confirmed.',
        }, status=status.HTTP_201_CREATED)


class PublicMemberLookupView(APIView):
    """Public endpoint: look up member name/email by registration code."""
    permission_classes = [AllowAny]

    def get(self, request):
        code = request.query_params.get('code', '').strip()
        if not code:
            return Response({'found': False})
        try:
            member = RegisteredMember.objects.get(registration_code__iexact=code)
            return Response({
                'found': True,
                'full_name': member.full_name,
                'email': member.email or '',
            })
        except RegisteredMember.DoesNotExist:
            return Response({'found': False, 'message': 'Registration code not found.'})


def get_members_for_event(event):
    """Return members eligible for an event based on category + package match.

    Rules (mirrors ScanBarcodeView package check):
    - event.event_type == 'ALL' (or blank): every member in the category qualifies.
    - otherwise: only members whose package_name contains the event_type string.
    """
    if not event.category:
        return RegisteredMember.objects.none()
    qs = RegisteredMember.objects.filter(event_category=event.category)
    if event.event_type and event.event_type != 'ALL':
        qs = qs.filter(package_name__icontains=event.event_type)
    return qs


class RegisteredMemberViewSet(viewsets.ModelViewSet):
    serializer_class = RegisteredMemberSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = None  # Return all members for the selected event (no page limit)

    def get_queryset(self):
        qs = RegisteredMember.objects.select_related('event_category').all()
        category_id = self.request.query_params.get('category_id')
        event_id = self.request.query_params.get('event_id')  # convenience: resolve to category
        search = self.request.query_params.get('search')
        payment_status = self.request.query_params.get('payment_status')
        attended = self.request.query_params.get('attended')  # 'yes' | 'no'

        if event_id:
            try:
                event = Event.objects.select_related('category').get(id=event_id)
                eligible_ids = get_members_for_event(event).values_list('id', flat=True)
                qs = qs.filter(id__in=eligible_ids)
            except Event.DoesNotExist:
                qs = qs.none()
        elif category_id:
            qs = qs.filter(event_category_id=category_id)
        if search:
            qs = qs.filter(
                full_name__icontains=search
            ) | qs.filter(registration_code__icontains=search) | qs.filter(email__icontains=search)
        if payment_status:
            qs = qs.filter(payment_status__iexact=payment_status)
        if attended and event_id:
            checked_in_ids = AttendanceRecord.objects.filter(
                event_id=event_id, scan_type='CHECK_IN'
            ).values_list('member_id', flat=True)
            if attended == 'yes':
                qs = qs.filter(id__in=checked_in_ids)
            elif attended == 'no':
                qs = qs.exclude(id__in=checked_in_ids)
        return qs

    def get_permissions(self):
        if self.action in ['list', 'retrieve']:
            return [IsAuthenticated()]
        return [IsAdminUser()]


class AttendanceRecordViewSet(viewsets.ModelViewSet):
    serializer_class = AttendanceRecordSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        qs = AttendanceRecord.objects.select_related('member', 'event', 'recorded_by').all()
        event_id = self.request.query_params.get('event_id')
        search = self.request.query_params.get('search')

        if event_id:
            qs = qs.filter(event_id=event_id)
        if search:
            qs = qs.filter(member__full_name__icontains=search) | qs.filter(member__registration_code__icontains=search)
        return qs

    def get_permissions(self):
        if self.action in ['list', 'retrieve']:
            return [IsAuthenticated()]
        return [IsAdminUser()]


class ScannerAssignmentViewSet(viewsets.ModelViewSet):
    serializer_class = ScannerAssignmentSerializer
    permission_classes = [IsAdminUser]

    def get_queryset(self):
        qs = ScannerAssignment.objects.select_related('user', 'event').all()
        user_id = self.request.query_params.get('user_id')
        event_id = self.request.query_params.get('event_id')
        if user_id:
            qs = qs.filter(user_id=user_id)
        if event_id:
            qs = qs.filter(event_id=event_id)
        return qs


class MyAssignmentsView(generics.ListAPIView):
    serializer_class = ScannerAssignmentSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return ScannerAssignment.objects.filter(
            user=self.request.user, is_active=True
        ).select_related('event')


class ScanBarcodeView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        serializer = ScanBarcodeSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        registration_code = serializer.validated_data['registration_code'].strip()
        event_id = serializer.validated_data['event_id']
        scan_type = serializer.validated_data.get('scan_type', 'CHECK_IN')

        try:
            event = Event.objects.select_related('category').get(id=event_id)
        except Event.DoesNotExist:
            return Response({'success': False, 'message': 'Event not found.'}, status=status.HTTP_404_NOT_FOUND)

        # Verify scanner has access to this event (superusers bypass this)
        if not request.user.is_superuser:
            has_assignment = ScannerAssignment.objects.filter(
                user=request.user, event=event, is_active=True
            ).exists()
            if not has_assignment:
                return Response({'success': False, 'message': 'You are not assigned to this event.'}, status=status.HTTP_403_FORBIDDEN)

        # Look up member
        member = None
        member_data = None

        try:
            member = RegisteredMember.objects.select_related('event_category').get(
                registration_code=registration_code
            )
            member_data = {
                'full_name': member.full_name,
                'email': member.email,
                'registration_code': member.registration_code,
                'event_category': member.event_category.name if member.event_category else 'N/A',
                'package_name': member.package_name or 'N/A',
                'payment_status': member.payment_status or 'N/A',
                'source': 'attendance',
            }
        except RegisteredMember.DoesNotExist:
            pass

        if member is None:
            return Response({
                'success': False,
                'already_attended': False,
                'message': 'Registration code not found. Member is not in the system.',
            })

        # ── Category check ──────────────────────────────────────────────────────
        if member.event_category and event.category:
            if member.event_category != event.category:
                return Response({
                    'success': False,
                    'already_attended': False,
                    'package_mismatch': True,
                    'message': (
                        f'Category mismatch: member is registered under "{member.event_category.name}" '
                        f'but this event belongs to "{event.category.name}".'
                    ),
                    'member': member_data,
                })

        # ── Package check ────────────────────────────────────────────────────────
        if event.event_type and event.event_type != 'ALL':
            pkg_upper = (member.package_name or '').upper()
            if event.event_type.upper() not in pkg_upper:
                return Response({
                    'success': False,
                    'already_attended': False,
                    'package_mismatch': True,
                    'message': (
                        f'Access denied. Member\'s package "{member.package_name or "N/A"}" '
                        f'does not include {event.event_type.title()}. '
                        f'Please advise member on correct entry point.'
                    ),
                    'member': member_data,
                })

        # ── Sequence validation ──────────────────────────────────────────────────
        # SESSION and CHECK_OUT require a prior CHECK_IN
        existing_types = set(
            AttendanceRecord.objects.filter(member=member, event=event)
            .values_list('scan_type', flat=True)
        )
        if scan_type in ('SESSION', 'CHECK_OUT') and 'CHECK_IN' not in existing_types:
            return Response({
                'success': False,
                'already_attended': False,
                'message': f'Cannot record {scan_type.replace("_", " ").title()} — member has not checked in yet.',
                'member': member_data,
            })

        # ── Duplicate scan_type check ────────────────────────────────────────────
        if scan_type in existing_types:
            existing = AttendanceRecord.objects.get(member=member, event=event, scan_type=scan_type)
            attendance_status = member.get_attendance_status(event_id)
            return Response({
                'success': True,
                'already_attended': True,
                'attendance_record_id': existing.id,
                'scan_type': scan_type,
                'attendance_status': attendance_status,
                'message': f'Member has already been recorded for {existing.get_scan_type_display()}.',
                'scan_time': existing.scan_time,
                'member': member_data,
            })

        # ── Record scan ──────────────────────────────────────────────────────────
        record = AttendanceRecord.objects.create(
            member=member,
            event=event,
            scan_type=scan_type,
            scan_time=timezone.now(),
            recorded_by=request.user,
        )
        attendance_status = member.get_attendance_status(event_id)

        scan_type_labels = {
            'CHECK_IN': 'Check-In recorded successfully.',
            'SESSION': 'Session Verification recorded.',
            'CHECK_OUT': 'Check-Out recorded successfully.',
        }

        return Response({
            'success': True,
            'already_attended': False,
            'attendance_record_id': record.id,
            'scan_type': scan_type,
            'attendance_status': attendance_status,
            'message': scan_type_labels.get(scan_type, 'Scan recorded.'),
            'scan_time': record.scan_time,
            'member': member_data,
        })


class UploadCSVView(APIView):
    permission_classes = [IsAdminUser]
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request):
        serializer = CSVUploadSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        csv_file = serializer.validated_data['csv_file']
        category_id = serializer.validated_data.get('event_category_id')

        from apps.events.models import EventCategory
        event_category = None
        if category_id:
            try:
                event_category = EventCategory.objects.get(id=category_id)
            except EventCategory.DoesNotExist:
                return Response({'error': 'Event category not found.'}, status=status.HTTP_404_NOT_FOUND)

        try:
            decoded = csv_file.read().decode('utf-8-sig')
            reader = csv.DictReader(io.StringIO(decoded))

            created_count = 0
            updated_count = 0
            errors = []

            for i, row in enumerate(reader, start=2):
                reg_code = row.get('Registration Code', '').strip()
                if not reg_code:
                    errors.append(f'Row {i}: Missing registration code, skipped.')
                    continue

                defaults = {
                    'email': row.get('Email', '').strip(),
                    'full_name': row.get('Full Name', '').strip(),
                    'status': row.get('Status', '').strip(),
                    'payment_status': row.get('Payment Status', '').strip(),
                    'package_name': row.get('Package Name', '').strip(),
                    'package_description': row.get('Package Description', '').strip(),
                    'activity_price': row.get('Activity Price', 0) or 0,
                }
                if event_category:
                    defaults['event_category'] = event_category

                _, created = RegisteredMember.objects.update_or_create(
                    registration_code=reg_code,
                    defaults=defaults,
                )
                if created:
                    created_count += 1
                else:
                    updated_count += 1

            return Response({
                'success': True,
                'created': created_count,
                'updated': updated_count,
                'errors': errors,
                'message': f'Import complete. {created_count} created, {updated_count} updated.',
            })
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)


class UndoAttendanceView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, record_id):
        try:
            record = AttendanceRecord.objects.select_related('member', 'event').get(id=record_id)
        except AttendanceRecord.DoesNotExist:
            return Response({'error': 'Attendance record not found.'}, status=status.HTTP_404_NOT_FOUND)

        if not request.user.is_superuser and record.recorded_by != request.user:
            return Response(
                {'error': 'You can only undo records you scanned yourself.'},
                status=status.HTTP_403_FORBIDDEN
            )

        member_name = record.member.full_name
        event_name = record.event.name
        record.delete()
        return Response({
            'success': True,
            'message': f'Attendance for {member_name} at {event_name} has been removed.',
        })


class DashboardStatsView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        event_id = request.query_params.get('event_id')

        events_qs = Event.objects.filter(is_archived=False, is_active=True)
        if event_id:
            events_qs = events_qs.filter(id=event_id)

        event_ids = events_qs.values_list('id', flat=True)

        # Members registered under categories that have at least one event
        category_ids = events_qs.exclude(
            category=None
        ).values_list('category_id', flat=True).distinct()
        total_members = RegisteredMember.objects.filter(
            event_category_id__in=category_ids
        ).count()

        # Per-scan-type unique member counts across all events
        total_checked_in = AttendanceRecord.objects.filter(
            event_id__in=event_ids, scan_type='CHECK_IN'
        ).values('member').distinct().count()

        total_sessions = AttendanceRecord.objects.filter(
            event_id__in=event_ids, scan_type='SESSION'
        ).values('member').distinct().count()

        total_checked_out = AttendanceRecord.objects.filter(
            event_id__in=event_ids, scan_type='CHECK_OUT'
        ).values('member').distinct().count()

        # Full attendance: members who have both CHECK_IN and CHECK_OUT
        total_full_attendance = AttendanceRecord.objects.filter(
            event_id__in=event_ids, scan_type='CHECK_IN'
        ).order_by().values('member').intersection(
            AttendanceRecord.objects.filter(
                event_id__in=event_ids, scan_type='CHECK_OUT'
            ).order_by().values('member')
        ).count()

        attendance_pct = round((total_checked_in / total_members * 100), 1) if total_members else 0

        event_stats = []
        for event in events_qs.order_by('start_date'):
            members_count = get_members_for_event(event).count()

            ev_checked_in = AttendanceRecord.objects.filter(
                event=event, scan_type='CHECK_IN'
            ).values('member').distinct().count()

            ev_sessions = AttendanceRecord.objects.filter(
                event=event, scan_type='SESSION'
            ).values('member').distinct().count()

            ev_checked_out = AttendanceRecord.objects.filter(
                event=event, scan_type='CHECK_OUT'
            ).values('member').distinct().count()

            ev_full = AttendanceRecord.objects.filter(
                event=event, scan_type='CHECK_IN'
            ).order_by().values('member').intersection(
                AttendanceRecord.objects.filter(
                    event=event, scan_type='CHECK_OUT'
                ).order_by().values('member')
            ).count()

            pct = round((ev_checked_in / members_count * 100), 1) if members_count else 0
            event_stats.append({
                'id': event.id,
                'name': event.name,
                'date': event.start_date.date(),
                'total_members': members_count,
                'checked_in': ev_checked_in,
                'sessions': ev_sessions,
                'checked_out': ev_checked_out,
                'full_attendance': ev_full,
                'percentage': pct,
            })

        return Response({
            'total_members': total_members,
            'total_checked_in': total_checked_in,
            'total_sessions': total_sessions,
            'total_checked_out': total_checked_out,
            'total_full_attendance': total_full_attendance,
            'attendance_percentage': attendance_pct,
            'total_events': events_qs.count(),
            'event_stats': event_stats,
        })


class EMSConfigView(APIView):
    """Returns EMS integration config available to the frontend (no credentials)."""
    permission_classes = [IsAdminUser]

    def get(self, request):
        from django.conf import settings
        configured = bool(settings.EMS_API_USERNAME and settings.EMS_API_PASSWORD)
        return Response({
            'configured': configured,
            'base_url': settings.EMS_API_BASE_URL,
            'event_types': ['AGM', 'CONFERENCE', 'TRAINING', 'EXPO', 'GALA', 'WORKSHOP'],
        })


class ImportFromEMSView(APIView):
    """
    Pull paid registrations from the external ICTAZ EMS API and upsert
    them as RegisteredMember records in this system.

    POST body:
        event_category_id  (int)   - our EventCategory pk to link members to
        ems_event_type     (str)   - EMS eventType param, e.g. 'AGM', 'CONFERENCE'
    """
    permission_classes = [IsAdminUser]

    def post(self, request):
        from django.conf import settings
        from apps.events.models import EventCategory
        from .ems_service import EMSApiClient

        event_category_id = request.data.get('event_category_id')
        ems_event_type = (request.data.get('ems_event_type') or '').strip()

        if not event_category_id:
            return Response({'detail': 'event_category_id is required.'}, status=status.HTTP_400_BAD_REQUEST)
        if not ems_event_type:
            return Response({'detail': 'ems_event_type is required.'}, status=status.HTTP_400_BAD_REQUEST)
        if not settings.EMS_API_USERNAME or not settings.EMS_API_PASSWORD:
            return Response(
                {'detail': 'EMS API credentials are not configured. Set EMS_API_USERNAME and EMS_API_PASSWORD in the environment.'},
                status=status.HTTP_503_SERVICE_UNAVAILABLE,
            )

        try:
            category = EventCategory.objects.get(pk=event_category_id)
        except EventCategory.DoesNotExist:
            return Response({'detail': 'Event category not found.'}, status=status.HTTP_404_NOT_FOUND)

        # Fetch from EMS
        try:
            client = EMSApiClient()
            members_data = client.fetch_paid_registrations(ems_event_type)
        except Exception as exc:
            return Response(
                {'detail': f'Failed to fetch from EMS API: {str(exc)}'},
                status=status.HTTP_502_BAD_GATEWAY,
            )

        if not isinstance(members_data, list):
            return Response(
                {'detail': 'Unexpected response format from EMS API.'},
                status=status.HTTP_502_BAD_GATEWAY,
            )

        created_count = 0
        updated_count = 0
        skipped_count = 0

        for entry in members_data:
            reg_code = (entry.get('registrationCode') or '').strip()
            if not reg_code:
                skipped_count += 1
                continue

            training_name = entry.get('trainingName') or ''
            package_name = (entry.get('packageOrActivityName') or '').strip()

            defaults = {
                'full_name': (entry.get('fullName') or '').strip(),
                'email': (entry.get('userEmail') or '').strip(),
                'event_category': category,
                'membership_number': (entry.get('membershipNumber') or '').strip(),
                'document_number': (entry.get('documentNumber') or '').strip(),
                'phone_number': (entry.get('phoneNumber') or '').strip(),
                'package_name': package_name,
                'package_description': training_name,
                'payment_status': (entry.get('paymentStatus') or '').strip(),
                'activity_price': entry.get('price') or 0,
                'status': 'active',
            }

            member, created = RegisteredMember.objects.update_or_create(
                registration_code=reg_code,
                defaults=defaults,
            )

            if created:
                created_count += 1
            else:
                updated_count += 1

        return Response({
            'success': True,
            'event_category': category.name,
            'ems_event_type': ems_event_type,
            'total_fetched': len(members_data),
            'created': created_count,
            'updated': updated_count,
            'skipped': skipped_count,
        }, status=status.HTTP_200_OK)
