import csv
from io import StringIO
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.http import HttpResponse
from django.db.models import Q

from .models import CPDConfiguration
from .serializers import CPDConfigurationSerializer, CPDExportRequestSerializer, BulkLookupRequestSerializer
from .services import MembershipAPIService
from apps.events.models import Event
from apps.attendance.models import RegisteredMember, AttendanceRecord


class CPDConfigurationViewSet(viewsets.ModelViewSet):
    queryset = CPDConfiguration.objects.all()
    serializer_class = CPDConfigurationSerializer
    permission_classes = [IsAuthenticated]
    
    @action(detail=False, methods=['post'])
    def set_cpd_points(self, request):
        """Set CPD points for an event"""
        event_id = request.data.get('event_id')
        cpd_points = request.data.get('cpd_points', 0.0)
        
        try:
            event = Event.objects.get(id=event_id)
            config, created = CPDConfiguration.objects.get_or_create(
                event=event,
                defaults={'cpd_points': cpd_points}
            )
            if not created:
                config.cpd_points = cpd_points
                config.save()
            
            serializer = self.get_serializer(config)
            return Response(serializer.data)
        except Event.DoesNotExist:
            return Response(
                {'error': 'Event not found'},
                status=status.HTTP_404_NOT_FOUND
            )
    
    @action(detail=False, methods=['post'])
    def export_cpd(self, request):
        """
        Export CPD data for an event with membership system enrichment
        """
        serializer = CPDExportRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        event_id = serializer.validated_data['event_id']
        cpd_points = serializer.validated_data.get('cpd_points')
        source_filter = request.data.get('source_filter', 'all')  # Get source filter from request
        
        try:
            event = Event.objects.get(id=event_id)
            
            # Update or create CPD configuration if points provided
            if cpd_points is not None:
                CPDConfiguration.objects.update_or_create(
                    event=event,
                    defaults={'cpd_points': cpd_points}
                )
                event_cpd_points = float(cpd_points)
            else:
                # Get CPD points from saved config
                try:
                    config = CPDConfiguration.objects.get(event=event)
                    event_cpd_points = float(config.cpd_points)
                except CPDConfiguration.DoesNotExist:
                    event_cpd_points = 0.0
            
            # Get members who actually attended (have CHECK_IN scan at minimum)
            # This ensures we only get members with attendance status:
            # - Attended Briefly (CHECK_IN only)
            # - Partial Attendance (CHECK_IN + SESSION)
            # - Full Attendance (CHECK_IN + CHECK_OUT)
            # - Verified Full Attendance (CHECK_IN + SESSION + CHECK_OUT)
            attended_member_ids = AttendanceRecord.objects.filter(
                event=event,
                scan_type='CHECK_IN'  # Must have at least checked in
            ).values_list('member_id', flat=True).distinct()
            
            members = RegisteredMember.objects.filter(
                id__in=attended_member_ids
            ).select_related('event_category')
            
            # Prepare CSV data using bulk parallel enrichment
            members_list = list(members)
            enriched_list = MembershipAPIService.bulk_enrich_members(members_list)
            
            # Apply source filter
            if source_filter == 'membership':
                enriched_list = [m for m in enriched_list if m['source'] == 'membership_system']
            elif source_filter == 'attendance':
                enriched_list = [m for m in enriched_list if m['source'] == 'attendance_list']
            # 'all' or any other value - no filtering
            
            csv_data = []
            for enriched_data in enriched_list:
                csv_data.append({
                    'membership_number': enriched_data['membership_number'],
                    'national_id_type': enriched_data['national_id_type'],
                    'national_id_number': enriched_data['national_id_number'],
                    'first_name': enriched_data['first_name'],
                    'middle_name': enriched_data['middle_name'],
                    'last_name': enriched_data['last_name'],
                    'email': enriched_data['email'],
                    'mobile': enriched_data['mobile'],
                    'cpd_points': event_cpd_points if event_cpd_points > 0 else '',
                    'source': enriched_data['source']
                })
            
            # Generate CSV file
            output = StringIO()
            writer = csv.DictWriter(output, fieldnames=[
                'membership_number',
                'national_id_type',
                'national_id_number',
                'first_name',
                'middle_name',
                'last_name',
                'email',
                'mobile',
                'cpd_points'
            ])
            
            # Write header
            writer.writerow({
                'membership_number': 'Membership Number',
                'national_id_type': 'National ID Type',
                'national_id_number': 'National ID Number',
                'first_name': 'First Name',
                'middle_name': 'Middle Name',
                'last_name': 'Last Name',
                'email': 'Email',
                'mobile': 'Mobile',
                'cpd_points': 'CPD Points'
            })
            
            # Write data rows
            for row in csv_data:
                writer.writerow({
                    'membership_number': row['membership_number'],
                    'national_id_type': row['national_id_type'],
                    'national_id_number': row['national_id_number'],
                    'first_name': row['first_name'],
                    'middle_name': row['middle_name'],
                    'last_name': row['last_name'],
                    'email': row['email'],
                    'mobile': row['mobile'],
                    'cpd_points': row['cpd_points']
                })
            
            # Create HTTP response with CSV
            response = HttpResponse(output.getvalue(), content_type='text/csv')
            response['Content-Disposition'] = f'attachment; filename="cpd_export_{event.name.replace(" ", "_")}.csv"'
            
            return response
            
        except Event.DoesNotExist:
            return Response(
                {'error': 'Event not found'},
                status=status.HTTP_404_NOT_FOUND
            )
    
    @action(detail=False, methods=['post'])
    def preview_cpd_data(self, request):
        """
        Preview CPD data before export (for UI display)
        """
        serializer = CPDExportRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        event_id = serializer.validated_data['event_id']
        cpd_points = serializer.validated_data.get('cpd_points')
        
        try:
            event = Event.objects.get(id=event_id)
            
            # Get CPD points - prioritize request parameter over saved config
            if cpd_points is not None:
                event_cpd_points = float(cpd_points)
            else:
                try:
                    config = CPDConfiguration.objects.get(event=event)
                    event_cpd_points = float(config.cpd_points)
                except CPDConfiguration.DoesNotExist:
                    event_cpd_points = 0.0
            
            # Get members who actually attended (have CHECK_IN scan at minimum)
            attended_member_ids = AttendanceRecord.objects.filter(
                event=event,
                scan_type='CHECK_IN'  # Must have at least checked in
            ).values_list('member_id', flat=True).distinct()
            
            members = RegisteredMember.objects.filter(
                id__in=attended_member_ids
            ).select_related('event_category')
            
            # Prepare preview data using bulk parallel enrichment
            preview_members = list(members)  # Show all attended members
            enriched_list = MembershipAPIService.bulk_enrich_members(preview_members)
            
            preview_data = []
            for member, enriched_data in zip(preview_members, enriched_list):
                preview_data.append({
                    'registration_code': member.registration_code,
                    'membership_number': enriched_data['membership_number'],
                    'national_id_type': enriched_data['national_id_type'],
                    'national_id_number': enriched_data['national_id_number'],
                    'first_name': enriched_data['first_name'],
                    'middle_name': enriched_data['middle_name'],
                    'last_name': enriched_data['last_name'],
                    'email': enriched_data['email'],
                    'mobile': enriched_data['mobile'],
                    'cpd_points': event_cpd_points,
                    'source': enriched_data['source']
                })
            
            return Response({
                'event': {
                    'id': event.id,
                    'name': event.name
                },
                'total_members': members.count(),
                'cpd_points': event_cpd_points,
                'preview_data': preview_data
            })
            
        except Event.DoesNotExist:
            return Response(
                {'error': 'Event not found'},
                status=status.HTTP_404_NOT_FOUND
            )
    
    @action(detail=False, methods=['post'])
    def bulk_lookup(self, request):
        """
        Upload CSV/Excel file with NRC/Passport numbers and lookup in membership system
        """
        from .bulk_lookup import BulkLookupProcessor
        
        serializer = BulkLookupRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        uploaded_file = serializer.validated_data['file']
        cpd_points = serializer.validated_data.get('cpd_points', 0.0)
        
        # Parse the file
        document_numbers, parse_errors = BulkLookupProcessor.parse_file(uploaded_file)
        
        if not document_numbers and parse_errors:
            return Response(
                {'error': 'Failed to parse file', 'details': parse_errors},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Prepare lookup data
        lookup_data = []
        for doc_num in document_numbers:
            id_type = BulkLookupProcessor.detect_id_type(doc_num)
            lookup_data.append({
                'document_number': doc_num,
                'id_type': id_type
            })
        
        # Perform bulk lookup using membership API
        results = []
        found_count = 0
        not_found_count = 0
        
        for item in lookup_data:
            doc_num = item['document_number']
            id_type = item['id_type']
            
            # Lookup in membership system
            member_data = MembershipAPIService.lookup_member(id_type, doc_num)
            
            if member_data:
                found_count += 1
                results.append({
                    'document_number': doc_num,
                    'id_type': id_type,
                    'found': True,
                    'membership_number': member_data.get('membership_number', ''),
                    'first_name': member_data.get('first_name', ''),
                    'middle_name': member_data.get('middle_name', ''),
                    'last_name': member_data.get('last_name', ''),
                    'email': member_data.get('email', ''),
                    'mobile': member_data.get('mobile', ''),
                    'cpd_points': cpd_points if cpd_points else '',
                    'source': 'membership_system'
                })
            else:
                not_found_count += 1
                results.append({
                    'document_number': doc_num,
                    'id_type': id_type,
                    'found': False,
                    'membership_number': '',
                    'first_name': '',
                    'middle_name': '',
                    'last_name': '',
                    'email': '',
                    'mobile': '',
                    'cpd_points': cpd_points if cpd_points else '',
                    'source': 'not_found'
                })
        
        return Response({
            'success': True,
            'total_uploaded': len(document_numbers),
            'found': found_count,
            'not_found': not_found_count,
            'parse_errors': parse_errors,
            'results': results
        })
    
    @action(detail=False, methods=['post'])
    def export_bulk_lookup(self, request):
        """
        Export bulk lookup results as CSV
        """
        results = request.data.get('results', [])
        cpd_points = request.data.get('cpd_points', '')
        
        if not results:
            return Response(
                {'error': 'No results to export'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Generate CSV
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = f'attachment; filename="bulk_lookup_results.csv"'
        
        writer = csv.writer(response)
        writer.writerow([
            'Membership Number',
            'National ID Type',
            'National ID Number',
            'First Name',
            'Middle Name',
            'Last Name',
            'Email',
            'Mobile',
            'CPD Points',
            'Status'
        ])
        
        for result in results:
            writer.writerow([
                result.get('membership_number', ''),
                result.get('id_type', ''),
                result.get('document_number', ''),
                result.get('first_name', ''),
                result.get('middle_name', ''),
                result.get('last_name', ''),
                result.get('email', ''),
                result.get('mobile', ''),
                cpd_points if cpd_points else '',
                'Found' if result.get('found') else 'Not Found'
            ])
        
        return response
