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.shortcuts import get_object_or_404
from datetime import date
from payroll.models import (
    PayrollIntegration,
    EmployeeMapping,
    ProjectMapping,
    PayrollSubmission
)
from payroll.serializers import (
    PayrollIntegrationSerializer,
    EmployeeMappingSerializer,
    ProjectMappingSerializer,
    PayrollSubmissionSerializer,
    PayrollSubmitRequestSerializer
)
from payroll.services.payroll_service import PayrollService
from payroll.services.mapping_service import MappingService


class PayrollIntegrationViewSet(viewsets.ModelViewSet):
    """ViewSet for managing payroll integrations"""
    serializer_class = PayrollIntegrationSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        # Filter by company if company_id is provided
        company_id = self.request.query_params.get('company_id')
        queryset = PayrollIntegration.objects.all()
        if company_id:
            queryset = queryset.filter(company_id=company_id)
        return queryset
    
    def get_serializer_context(self):
        """Add request to serializer context"""
        context = super().get_serializer_context()
        context['request'] = self.request
        return context
    
    def list(self, request, *args, **kwargs):
        """Override list to handle serialization safely"""
        try:
            queryset = self.filter_queryset(self.get_queryset())
            # Evaluate queryset to list to avoid lazy evaluation issues
            queryset_list = list(queryset)
            serializer = self.get_serializer(queryset_list, many=True)
            return Response(serializer.data)
        except ValueError as e:
            if "expected a number" in str(e):
                import traceback
                traceback.print_exc()
                return Response({
                    'error': 'Serialization error',
                    'detail': str(e)
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            raise
    
    @action(detail=True, methods=['post'])
    def test_connection(self, request, pk=None):
        """Test connection to payroll system"""
        integration = self.get_object()
        
        if integration.provider == 'none':
            return Response({
                'valid': False,
                'message': 'No payroll provider configured'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            service = PayrollService(integration)
            result = service.validate_connection()
            return Response(result)
        except Exception as e:
            return Response({
                'valid': False,
                'message': str(e)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class EmployeeMappingViewSet(viewsets.ModelViewSet):
    """ViewSet for managing employee mappings"""
    serializer_class = EmployeeMappingSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        integration_id = self.request.query_params.get('integration_id')
        if integration_id:
            return EmployeeMapping.objects.filter(payroll_integration_id=integration_id)
        return EmployeeMapping.objects.all()


class ProjectMappingViewSet(viewsets.ModelViewSet):
    """ViewSet for managing project mappings"""
    serializer_class = ProjectMappingSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        integration_id = self.request.query_params.get('integration_id')
        if integration_id:
            return ProjectMapping.objects.filter(payroll_integration_id=integration_id)
        return ProjectMapping.objects.all()


class PayrollSubmissionViewSet(viewsets.ReadOnlyModelViewSet):
    """ViewSet for viewing payroll submissions"""
    serializer_class = PayrollSubmissionSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        integration_id = self.request.query_params.get('integration_id')
        user_id = self.request.query_params.get('user_id')
        
        queryset = PayrollSubmission.objects.all()
        
        if integration_id:
            queryset = queryset.filter(payroll_integration_id=integration_id)
        if user_id:
            queryset = queryset.filter(user_id=user_id)
        
        return queryset
    
    @action(detail=False, methods=['post'])
    def submit(self, request):
        """Submit timesheet to payroll system"""
        submit_serializer = PayrollSubmitRequestSerializer(data=request.data)
        if not submit_serializer.is_valid():
            return Response(submit_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
        data = submit_serializer.validated_data
        user_id = data['user_id']
        period_start = data['period_start']
        period_end = data['period_end']
        stamp_ids = data.get('stamp_ids', [])
        
        # Get the payroll integration for the user's company
        # For now, get the first active integration
        # In production, you might want to get it from user's company
        from user.models import User
        try:
            user = User.objects.get(id=user_id)
            # Get integration_id from request if provided, otherwise use first active
            integration_id = request.data.get('integration_id')
            if integration_id:
                integration = PayrollIntegration.objects.filter(id=integration_id, is_active=True).first()
            else:
                integration = PayrollIntegration.objects.filter(is_active=True).first()
            
            if not integration:
                return Response({
                    'error': 'No active payroll integration found'
                }, status=status.HTTP_400_BAD_REQUEST)
            
            service = PayrollService(integration)
            submission = service.submit_timesheet(
                user_id=str(user_id),
                period_start=period_start,
                period_end=period_end,
                stamp_ids=[str(sid) for sid in stamp_ids] if stamp_ids else None
            )
            
            serializer = PayrollSubmissionSerializer(submission)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
            
        except User.DoesNotExist:
            return Response({
                'error': 'User not found'
            }, status=status.HTTP_404_NOT_FOUND)
        except ValueError as e:
            return Response({
                'error': str(e)
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            return Response({
                'error': str(e)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
