# payslips/views.py

from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from django.db import models
from rest_framework.response import Response
from django.db.models import Q, Sum, Count, Avg, F
from django.shortcuts import get_object_or_404
from people.serializers import SimpleTeacherSerializer
from django.db import IntegrityError, transaction
from django.utils import timezone
from rest_framework.permissions import IsAuthenticated

from people.models import Teacher
from .models import (
    TeacherPayStructure, 
    MonthlyPaySlip, 
    PaymentTransaction, 
    PaySlipTemplate
)
from .serializers import (
    TeacherPayStructureSerializer,
    TeacherPayStructureListSerializer,
    MonthlyPaySlipSerializer,
    MonthlyPaySlipListSerializer,
    MonthlyPaySlipDetailSerializer,
    PaymentTransactionSerializer,
    PaymentTransactionListSerializer,
    PaySlipTemplateSerializer,
    PaySlipTemplateListSerializer,
    GeneratePaySlipSerializer,
    BulkPaySlipGenerateSerializer,
    PaySlipUpdateSerializer,
    PaySlipApprovalSerializer,
    PaySlipSummarySerializer,
    TeacherPaySummarySerializer,
    RecordPaymentSerializer,
    PaySlipTemplateListSerializer,
    PaySlipTemplateSerializer
)

import logging
logger = logging.getLogger(__name__)

class TeacherPayStructureViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Teacher Pay Structure CRUD operations
    Stores default/base salary for each teacher
    """

    queryset = TeacherPayStructure.objects.filter(is_active=True)
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['teacher__first_name', 'teacher__last_name', 'teacher__employee_id']
    ordering_fields = ['base_salary', 'effective_from', 'created_at']
    ordering = ['-effective_from']

    def get_serializer_class(self):
        if self.action == 'list':
            return TeacherPayStructureListSerializer
        return TeacherPayStructureSerializer

    def get_queryset(self):
        queryset = super().get_queryset().select_related('teacher', 'created_by')
        
        teacher_id = self.request.query_params.get('teacher_id')
        if teacher_id:
            queryset = queryset.filter(teacher_id=teacher_id)
        
        is_active = self.request.query_params.get('is_active')
        if is_active is not None:
            queryset = queryset.filter(is_active=is_active.lower() == 'true')
        
        search = self.request.query_params.get('search', '')
        if search:
            queryset = queryset.filter(
                Q(teacher__first_name__icontains=search) |
                Q(teacher__last_name__icontains=search) |
                Q(teacher__employee_id__icontains=search)
            )
        
        return queryset

    @action(detail=True, methods=['post'])
    def deactivate(self, request, pk=None):
        """Deactivate a pay structure"""
        pay_structure = self.get_object()
        pay_structure.is_active = False
        pay_structure.effective_to = timezone.now().date()
        pay_structure.save()
        serializer = self.get_serializer(pay_structure)
        return Response(serializer.data)

    @action(detail=False, methods=['get'], url_path='teachers-with-pay-structure')
    def teachers_with_pay_structure(self, request):
        """Get all teachers who have an active pay structure"""
        search = request.query_params.get('search', '')
        
        # Get all teacher IDs with active pay structures
        teacher_ids = TeacherPayStructure.objects.filter(
            is_active=True
        ).values_list('teacher_id', flat=True).distinct()
        
        # Get teachers with those IDs
        teachers = Teacher.objects.filter(
            id__in=teacher_ids,
            is_active=True
        )
        
        if search:
            teachers = teachers.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(employee_id__icontains=search)
            )
        
        teachers = teachers.order_by('first_name', 'last_name')
        
        # Pagination
        page = self.paginate_queryset(teachers)
        if page is not None:
            serializer = SimpleTeacherSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        
        serializer = SimpleTeacherSerializer(teachers, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def current(self, request):
        """Get current active pay structure for a teacher"""
        teacher_id = request.query_params.get('teacher_id')
        if not teacher_id:
            return Response(
                {"error": "teacher_id is required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            pay_structure = TeacherPayStructure.objects.get(
                teacher_id=teacher_id,
                is_active=True
            )
            serializer = self.get_serializer(pay_structure)
            return Response(serializer.data)
        except TeacherPayStructure.DoesNotExist:
            return Response(
                {"error": "No active pay structure found for this teacher"},
                status=status.HTTP_404_NOT_FOUND
            )

class MonthlyPaySlipViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Monthly Pay Slip operations
    """

    queryset = MonthlyPaySlip.objects.filter(is_active=True)
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['pay_slip_number', 'teacher__first_name', 'teacher__last_name', 'teacher__employee_id']
    ordering_fields = ['year', 'month', 'net_pay', 'created_at', 'status']
    ordering = ['-year', '-month']

    def get_serializer_class(self):
        if self.action == 'list':
            return MonthlyPaySlipListSerializer
        elif self.action == 'retrieve':
            return MonthlyPaySlipDetailSerializer
        return MonthlyPaySlipSerializer

    def get_queryset(self):
        queryset = super().get_queryset().select_related(
            'teacher', 'created_by', 'approved_by'
        ).prefetch_related('payment_transactions')
        
        teacher_id = self.request.query_params.get('teacher_id')
        if teacher_id:
            queryset = queryset.filter(teacher_id=teacher_id)
        
        year = self.request.query_params.get('year')
        if year:
            queryset = queryset.filter(year=year)
        
        month = self.request.query_params.get('month')
        if month:
            queryset = queryset.filter(month=month)
        
        status_filter = self.request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter.upper())
        
        from_date = self.request.query_params.get('from_date')
        if from_date:
            queryset = queryset.filter(created_at__date__gte=from_date)
        
        to_date = self.request.query_params.get('to_date')
        if to_date:
            queryset = queryset.filter(created_at__date__lte=to_date)
        
        search = self.request.query_params.get('search', '')
        if search:
            queryset = queryset.filter(
                Q(pay_slip_number__icontains=search) |
                Q(teacher__first_name__icontains=search) |
                Q(teacher__last_name__icontains=search) |
                Q(teacher__employee_id__icontains=search)
            )
        
        return queryset

    @action(detail=False, methods=['post'])
    def generate(self, request):
        """Generate pay slip for a specific teacher"""
        serializer = GeneratePaySlipSerializer(data=request.data)
        if serializer.is_valid():
            try:
                teacher_id = serializer.validated_data['teacher_id']
                month = serializer.validated_data['month']
                year = serializer.validated_data['year']
                
                existing = MonthlyPaySlip.objects.filter(
                    teacher_id=teacher_id,
                    month=month,
                    year=year,
                    is_active=True
                ).first()
                
                if existing:
                    return Response(
                        {"error": f"Pay slip already exists for {month}/{year}"},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                
                pay_structure = TeacherPayStructure.objects.filter(
                    teacher_id=teacher_id,
                    is_active=True
                ).first()
                
                if not pay_structure:
                    return Response(
                        {"error": "No active pay structure found for this teacher"},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                
                snapshot = {
                    'base_salary': str(pay_structure.base_salary),
                    'dearness_allowance': str(pay_structure.dearness_allowance or 0),
                    'house_rent_allowance': str(pay_structure.house_rent_allowance or 0),
                    'city_compensatory_allowance': str(pay_structure.city_compensatory_allowance or 0),
                    'travel_allowance': str(pay_structure.travel_allowance or 0),
                    'medical_allowance': str(pay_structure.medical_allowance or 0),
                    'special_allowance': str(pay_structure.special_allowance or 0),
                    'education_allowance': str(pay_structure.education_allowance or 0),
                    'telephone_allowance': str(pay_structure.telephone_allowance or 0),
                    'provident_fund_percentage': str(pay_structure.provident_fund_percentage or 0),
                    'esi_percentage': str(pay_structure.esi_percentage or 0),
                    'professional_tax_fixed': str(pay_structure.professional_tax_fixed or 0),
                }
                
                pf_amount = (pay_structure.base_salary * (pay_structure.provident_fund_percentage or 0) / 100)
                esi_amount = (pay_structure.base_salary * (pay_structure.esi_percentage or 0) / 100)
                
                pay_slip = MonthlyPaySlip.objects.create(
                    teacher_id=teacher_id,
                    month=month,
                    year=year,
                    pay_structure_snapshot=snapshot,
                    status='DRAFT',
                    created_by=request.user.teacher if hasattr(request.user, 'teacher') else None,
                    base_salary=pay_structure.base_salary,
                    dearness_allowance=pay_structure.dearness_allowance or 0,
                    house_rent_allowance=pay_structure.house_rent_allowance or 0,
                    city_compensatory_allowance=pay_structure.city_compensatory_allowance or 0,
                    travel_allowance=pay_structure.travel_allowance or 0,
                    medical_allowance=pay_structure.medical_allowance or 0,
                    special_allowance=pay_structure.special_allowance or 0,
                    education_allowance=pay_structure.education_allowance or 0,
                    telephone_allowance=pay_structure.telephone_allowance or 0,
                    performance_incentive=pay_structure.default_performance_incentive or 0,
                    special_class_incentive=pay_structure.default_special_class_incentive or 0,
                    subject_expert_incentive=pay_structure.default_subject_expert_incentive or 0,
                    leadership_allowance=pay_structure.default_leadership_allowance or 0,
                    provident_fund_employee=pf_amount,
                    esi_deduction=esi_amount,
                    professional_tax=pay_structure.professional_tax_fixed or 0,
                )
                
                pay_slip.save()
                
                serializer = MonthlyPaySlipDetailSerializer(pay_slip)
                return Response(serializer.data, status=status.HTTP_201_CREATED)
                
            except Exception as e:
                logger.error(f"Error generating pay slip: {str(e)}")
                return Response(
                    {"error": str(e)},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['post'])
    def bulk_generate(self, request):
        """Generate pay slips for multiple teachers"""
        serializer = BulkPaySlipGenerateSerializer(data=request.data)
        if serializer.is_valid():
            teacher_ids = serializer.validated_data['teacher_ids']
            month = serializer.validated_data['month']
            year = serializer.validated_data['year']
            
            created = []
            errors = []
            
            for teacher_id in teacher_ids:
                try:
                    existing = MonthlyPaySlip.objects.filter(
                        teacher_id=teacher_id,
                        month=month,
                        year=year,
                        is_active=True
                    ).first()
                    
                    if existing:
                        errors.append({
                            "teacher_id": teacher_id,
                            "error": f"Pay slip already exists for {month}/{year}"
                        })
                        continue
                    
                    pay_structure = TeacherPayStructure.objects.filter(
                        teacher_id=teacher_id,
                        is_active=True
                    ).first()
                    
                    if not pay_structure:
                        errors.append({
                            "teacher_id": teacher_id,
                            "error": "No active pay structure found"
                        })
                        continue
                    
                    snapshot = {
                        'base_salary': str(pay_structure.base_salary),
                        'dearness_allowance': str(pay_structure.dearness_allowance or 0),
                        'house_rent_allowance': str(pay_structure.house_rent_allowance or 0),
                        'city_compensatory_allowance': str(pay_structure.city_compensatory_allowance or 0),
                        'travel_allowance': str(pay_structure.travel_allowance or 0),
                        'medical_allowance': str(pay_structure.medical_allowance or 0),
                        'special_allowance': str(pay_structure.special_allowance or 0),
                        'education_allowance': str(pay_structure.education_allowance or 0),
                        'telephone_allowance': str(pay_structure.telephone_allowance or 0),
                        'provident_fund_percentage': str(pay_structure.provident_fund_percentage or 0),
                        'esi_percentage': str(pay_structure.esi_percentage or 0),
                        'professional_tax_fixed': str(pay_structure.professional_tax_fixed or 0),
                    }
                    
                    pf_amount = (pay_structure.base_salary * (pay_structure.provident_fund_percentage or 0) / 100)
                    esi_amount = (pay_structure.base_salary * (pay_structure.esi_percentage or 0) / 100)
                    
                    pay_slip = MonthlyPaySlip.objects.create(
                        teacher_id=teacher_id,
                        month=month,
                        year=year,
                        pay_structure_snapshot=snapshot,
                        status='DRAFT',
                        created_by=request.user.teacher if hasattr(request.user, 'teacher') else None,
                        base_salary=pay_structure.base_salary,
                        dearness_allowance=pay_structure.dearness_allowance or 0,
                        house_rent_allowance=pay_structure.house_rent_allowance or 0,
                        city_compensatory_allowance=pay_structure.city_compensatory_allowance or 0,
                        travel_allowance=pay_structure.travel_allowance or 0,
                        medical_allowance=pay_structure.medical_allowance or 0,
                        special_allowance=pay_structure.special_allowance or 0,
                        education_allowance=pay_structure.education_allowance or 0,
                        telephone_allowance=pay_structure.telephone_allowance or 0,
                        performance_incentive=pay_structure.default_performance_incentive or 0,
                        special_class_incentive=pay_structure.default_special_class_incentive or 0,
                        subject_expert_incentive=pay_structure.default_subject_expert_incentive or 0,
                        leadership_allowance=pay_structure.default_leadership_allowance or 0,
                        provident_fund_employee=pf_amount,
                        esi_deduction=esi_amount,
                        professional_tax=pay_structure.professional_tax_fixed or 0,
                    )
                    
                    pay_slip.save()
                    created.append({
                        "teacher_id": teacher_id,
                        "pay_slip_id": pay_slip.id,
                        "pay_slip_number": pay_slip.pay_slip_number
                    })
                    
                except Exception as e:
                    errors.append({
                        "teacher_id": teacher_id,
                        "error": str(e)
                    })
            
            return Response({
                "message": f"Generated {len(created)} pay slips",
                "created": created,
                "errors": errors if errors else None
            }, status=status.HTTP_201_CREATED)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def update_components(self, request, pk=None):
        """Update pay slip components (incentives, deductions, etc.)"""
        pay_slip = self.get_object()
        
        if pay_slip.status not in ['DRAFT', 'PENDING']:
            return Response(
                {"error": f"Cannot update pay slip with status {pay_slip.status}"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        serializer = PaySlipUpdateSerializer(data=request.data, partial=True)
        if serializer.is_valid():
            for field, value in serializer.validated_data.items():
                if value is not None:
                    setattr(pay_slip, field, value)
            
            pay_slip.save()
            
            result_serializer = MonthlyPaySlipDetailSerializer(pay_slip)
            return Response(result_serializer.data)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def submit_for_approval(self, request, pk=None):
        """Submit pay slip for approval"""
        pay_slip = self.get_object()
        
        if pay_slip.status != 'DRAFT':
            return Response(
                {"error": f"Cannot submit pay slip with status {pay_slip.status}"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        pay_slip.status = 'PENDING'
        pay_slip.save()
        
        serializer = MonthlyPaySlipDetailSerializer(pay_slip)
        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def approve(self, request, pk=None):
        """Approve a pay slip"""
        pay_slip = self.get_object()
        
        if pay_slip.status != 'PENDING':
            return Response(
                {"error": f"Cannot approve pay slip with status {pay_slip.status}"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        serializer = PaySlipApprovalSerializer(data=request.data)
        if serializer.is_valid():
            pay_slip.status = 'APPROVED'
            pay_slip.approved_by = request.user.teacher if hasattr(request.user, 'teacher') else None
            pay_slip.approved_at = timezone.now()
            pay_slip.hr_remarks = serializer.validated_data.get('remarks', '')
            pay_slip.save()
            
            result_serializer = MonthlyPaySlipDetailSerializer(pay_slip)
            return Response(result_serializer.data)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def reject(self, request, pk=None):
        """Reject a pay slip"""
        pay_slip = self.get_object()
        
        if pay_slip.status != 'PENDING':
            return Response(
                {"error": f"Cannot reject pay slip with status {pay_slip.status}"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        serializer = PaySlipApprovalSerializer(data=request.data)
        if serializer.is_valid():
            pay_slip.status = 'DRAFT'
            pay_slip.hr_remarks = serializer.validated_data.get('remarks', 'Rejected')
            pay_slip.save()
            
            result_serializer = MonthlyPaySlipDetailSerializer(pay_slip)
            return Response(result_serializer.data)
        
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def mark_as_paid(self, request, pk=None):
        """Mark pay slip as paid"""
        pay_slip = self.get_object()
        
        if pay_slip.status != 'APPROVED':
            return Response(
                {"error": f"Cannot mark as paid. Current status: {pay_slip.status}"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        pay_slip.status = 'PAID'
        pay_slip.save()
        
        serializer = MonthlyPaySlipDetailSerializer(pay_slip)
        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        """Cancel a pay slip"""
        pay_slip = self.get_object()
        
        if pay_slip.status == 'PAID':
            return Response(
                {"error": "Cannot cancel a paid pay slip"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        pay_slip.status = 'CANCELLED'
        pay_slip.is_active = False
        pay_slip.save()
        
        serializer = MonthlyPaySlipDetailSerializer(pay_slip)
        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def acknowledge(self, request, pk=None):
        """Teacher acknowledges pay slip"""
        pay_slip = self.get_object()
        
        if pay_slip.status != 'PAID':
            return Response(
                {"error": "Pay slip must be paid before acknowledgement"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        pay_slip.is_acknowledged = True
        pay_slip.acknowledged_at = timezone.now()
        pay_slip.save()
        
        serializer = MonthlyPaySlipDetailSerializer(pay_slip)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def summary(self, request):
        """Get summary of pay slips"""
        year = request.query_params.get('year', timezone.now().year)
        
        summary = MonthlyPaySlip.objects.filter(
            year=year,
            is_active=True
        ).aggregate(
            total_pay_slips=Count('id'),
            total_draft=Count('id', filter=Q(status='DRAFT')),
            total_pending=Count('id', filter=Q(status='PENDING')),
            total_approved=Count('id', filter=Q(status='APPROVED')),
            total_paid=Count('id', filter=Q(status='PAID')),
            total_cancelled=Count('id', filter=Q(status='CANCELLED')),
            total_net_pay=Sum('net_pay'),
            average_net_pay=Avg('net_pay')
        )
        
        monthly_breakdown = MonthlyPaySlip.objects.filter(
            year=year,
            is_active=True,
            status='PAID'
        ).values('month').annotate(
            total_net_pay=Sum('net_pay'),
            count=Count('id')
        ).order_by('month')
        
        return Response({
            "year": year,
            "summary": summary,
            "monthly_breakdown": monthly_breakdown
        })

    @action(detail=False, methods=['get'])
    def teacher_summary(self, request):
        """Get pay summary for a specific teacher"""
        teacher_id = request.query_params.get('teacher_id')
        if not teacher_id:
            return Response(
                {"error": "teacher_id is required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        year = request.query_params.get('year', timezone.now().year)
        
        pay_slips = MonthlyPaySlip.objects.filter(
            teacher_id=teacher_id,
            year=year,
            is_active=True
        ).order_by('month')
        
        total_earned = pay_slips.aggregate(total=Sum('net_pay'))['total'] or 0
        
        monthly_data = []
        for month in range(1, 13):
            pay_slip = pay_slips.filter(month=month).first()
            monthly_data.append({
                "month": month,
                "has_pay_slip": pay_slip is not None,
                "status": pay_slip.status if pay_slip else None,
                "net_pay": float(pay_slip.net_pay) if pay_slip and pay_slip.net_pay else 0,
                "pay_slip_number": pay_slip.pay_slip_number if pay_slip else None
            })
        
        return Response({
            "teacher_id": teacher_id,
            "year": year,
            "total_earned": float(total_earned),
            "monthly_data": monthly_data
        })

class PaymentTransactionViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Payment Transaction operations
    """

    # Remove is_active filter - PaymentTransaction doesn't have this field
    queryset = PaymentTransaction.objects.all()  # Changed from filter(is_active=True)
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['transaction_id', 'bank_reference', 'cheque_number']
    ordering_fields = ['payment_date', 'amount', 'status']
    ordering = ['-payment_date']

    def get_serializer_class(self):
        if self.action == 'list':
            return PaymentTransactionListSerializer
        return PaymentTransactionSerializer

    def get_queryset(self):
        queryset = super().get_queryset().select_related(
            'pay_slip', 'teacher', 'recorded_by'
        )
        
        pay_slip_id = self.request.query_params.get('pay_slip_id')
        if pay_slip_id:
            queryset = queryset.filter(pay_slip_id=pay_slip_id)
        
        teacher_id = self.request.query_params.get('teacher_id')
        if teacher_id:
            queryset = queryset.filter(teacher_id=teacher_id)
        
        payment_type = self.request.query_params.get('payment_type')
        if payment_type:
            queryset = queryset.filter(payment_type=payment_type)
        
        status_filter = self.request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter.upper())
        
        from_date = self.request.query_params.get('from_date')
        if from_date:
            queryset = queryset.filter(payment_date__date__gte=from_date)
        
        to_date = self.request.query_params.get('to_date')
        if to_date:
            queryset = queryset.filter(payment_date__date__lte=to_date)
        
        return queryset
class PaySlipTemplateViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Pay Slip Template operations
    """

    queryset = PaySlipTemplate.objects.filter(is_active=True)
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'designation']
    ordering_fields = ['name', 'created_at']
    ordering = ['name']

    def get_serializer_class(self):
        if self.action == 'list':
            return PaySlipTemplateListSerializer
        return PaySlipTemplateSerializer

    def get_queryset(self):
        queryset = super().get_queryset().prefetch_related('applicable_teachers')
        
        search = self.request.query_params.get('search', '')
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) |
                Q(designation__icontains=search)
            )
        
        return queryset

    @action(detail=True, methods=['post'])
    def apply_to_teachers(self, request, pk=None):
        """Apply template to multiple teachers"""
        template = self.get_object()
        teacher_ids = request.data.get('teacher_ids', [])
        
        if not teacher_ids:
            return Response(
                {"error": "teacher_ids list is required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        created = []
        errors = []
        
        for teacher_id in teacher_ids:
            try:
                teacher = Teacher.objects.get(id=teacher_id)
                
                existing = TeacherPayStructure.objects.filter(
                    teacher=teacher,
                    is_active=True
                ).first()
                
                if existing:
                    existing.base_salary = template.base_salary
                    existing.dearness_allowance = template.dearness_allowance
                    existing.house_rent_allowance = template.house_rent_allowance
                    existing.city_compensatory_allowance = template.city_compensatory_allowance
                    existing.travel_allowance = template.travel_allowance
                    existing.medical_allowance = template.medical_allowance
                    existing.special_allowance = template.special_allowance
                    existing.education_allowance = template.education_allowance
                    existing.telephone_allowance = template.telephone_allowance
                    existing.provident_fund_percentage = template.provident_fund_percentage
                    existing.esi_percentage = template.esi_percentage
                    existing.professional_tax_fixed = template.professional_tax_fixed
                    existing.effective_from = timezone.now().date()
                    existing.save()
                    created.append({"teacher_id": teacher_id, "action": "updated"})
                else:
                    pay_structure = TeacherPayStructure.objects.create(
                        teacher=teacher,
                        base_salary=template.base_salary,
                        dearness_allowance=template.dearness_allowance,
                        house_rent_allowance=template.house_rent_allowance,
                        city_compensatory_allowance=template.city_compensatory_allowance,
                        travel_allowance=template.travel_allowance,
                        medical_allowance=template.medical_allowance,
                        special_allowance=template.special_allowance,
                        education_allowance=template.education_allowance,
                        telephone_allowance=template.telephone_allowance,
                        provident_fund_percentage=template.provident_fund_percentage,
                        esi_percentage=template.esi_percentage,
                        professional_tax_fixed=template.professional_tax_fixed,
                        effective_from=timezone.now().date(),
                        is_active=True
                    )
                    created.append({"teacher_id": teacher_id, "action": "created"})
                    
            except Teacher.DoesNotExist:
                errors.append({"teacher_id": teacher_id, "error": "Teacher not found"})
            except Exception as e:
                errors.append({"teacher_id": teacher_id, "error": str(e)})
        
        return Response({
            "message": f"Applied template to {len(created)} teachers",
            "created": created,
            "errors": errors if errors else None
        })

    @action(detail=True, methods=['post'])
    def toggle_active(self, request, pk=None):
        """Toggle template active status"""
        template = self.get_object()
        template.is_active = not template.is_active
        template.save()
        serializer = self.get_serializer(template)
        return Response(serializer.data)
    
    
# Add these to your existing views.py

class PaymentTransactionViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Payment Transaction operations
    """

    queryset = PaymentTransaction.objects.all()
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['transaction_id', 'bank_reference', 'cheque_number', 'pay_slip__pay_slip_number']
    ordering_fields = ['payment_date', 'amount', 'status']
    ordering = ['-payment_date']

    def get_serializer_class(self):
        if self.action == 'list':
            return PaymentTransactionListSerializer
        return PaymentTransactionSerializer

    def get_queryset(self):
        queryset = super().get_queryset().select_related(
            'pay_slip', 'teacher', 'recorded_by'
        )
        
        pay_slip_id = self.request.query_params.get('pay_slip_id')
        if pay_slip_id:
            queryset = queryset.filter(pay_slip_id=pay_slip_id)
        
        teacher_id = self.request.query_params.get('teacher_id')
        if teacher_id:
            queryset = queryset.filter(teacher_id=teacher_id)
        
        payment_type = self.request.query_params.get('payment_type')
        if payment_type:
            queryset = queryset.filter(payment_type=payment_type)
        
        payment_method = self.request.query_params.get('payment_method')
        if payment_method:
            queryset = queryset.filter(payment_method=payment_method)
        
        status_filter = self.request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter.upper())
        
        from_date = self.request.query_params.get('from_date')
        if from_date:
            queryset = queryset.filter(payment_date__date__gte=from_date)
        
        to_date = self.request.query_params.get('to_date')
        if to_date:
            queryset = queryset.filter(payment_date__date__lte=to_date)
        
        return queryset

    @action(detail=False, methods=['post'])
    def record_payment(self, request):
        """Record a payment transaction for a pay slip"""
        serializer = RecordPaymentSerializer(data=request.data)
        
        if not serializer.is_valid():
            return Response(
                {"success": False, "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        data = serializer.validated_data
        pay_slip = data['pay_slip']
        amount = data['amount']
        
        with transaction.atomic():
            payment = PaymentTransaction.objects.create(
                pay_slip=pay_slip,
                teacher=pay_slip.teacher,
                payment_type=data.get('payment_type', 'FULL'),
                amount=amount,
                payment_method=data['payment_method'],
                payment_date=timezone.now(),
                transaction_id=data.get('transaction_id'),
                bank_reference=data.get('bank_reference'),
                cheque_number=data.get('cheque_number'),
                upi_id=data.get('upi_id'),
                bank_name=data.get('bank_name'),
                bank_account_number=data.get('bank_account_number'),
                bank_ifsc_code=data.get('bank_ifsc_code'),
                status='COMPLETED',
                remarks=data.get('remarks', ''),
                recorded_by=request.user.teacher if hasattr(request.user, 'teacher') else None
            )
            
            # Check if pay slip is fully paid
            total_paid = PaymentTransaction.objects.filter(
                pay_slip=pay_slip,
                status='COMPLETED'
            ).aggregate(total=models.Sum('amount'))['total'] or 0
            
            if total_paid >= float(pay_slip.net_pay):
                pay_slip.status = 'PAID'
                pay_slip.save(update_fields=['status'])
        
        result_serializer = PaymentTransactionSerializer(payment)
        return Response({
            "success": True,
            "message": "Payment recorded successfully",
            "data": result_serializer.data
        }, status=status.HTTP_201_CREATED)

    @action(detail=True, methods=['post'])
    def refund(self, request, pk=None):
        """Refund a payment transaction"""
        payment = self.get_object()
        
        if payment.status != 'COMPLETED':
            return Response(
                {"success": False, "message": "Only completed payments can be refunded"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        reason = request.data.get('reason', 'No reason provided')
        
        payment.status = 'REFUNDED'
        payment.remarks = f"Refunded: {reason}"
        payment.save()
        
        # Update pay slip status
        pay_slip = payment.pay_slip
        if pay_slip.status == 'PAID':
            pay_slip.status = 'APPROVED'
            pay_slip.save(update_fields=['status'])
        
        serializer = PaymentTransactionSerializer(payment)
        return Response({
            "success": True,
            "message": "Payment refunded successfully",
            "data": serializer.data
        })

class PaySlipTemplateViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Pay Slip Template operations
    Manage templates for creating teacher pay structures
    """

    queryset = PaySlipTemplate.objects.filter(is_active=True)
    permission_classes = [IsAuthenticated]
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'designation', 'description']
    ordering_fields = ['name', 'base_salary', 'created_at']
    ordering = ['name']

    def get_serializer_class(self):
        if self.action == 'list':
            return PaySlipTemplateListSerializer
        return PaySlipTemplateSerializer

    def get_queryset(self):
        queryset = super().get_queryset().prefetch_related('applicable_teachers', 'created_by')
        
        # Filter by active status
        is_active = self.request.query_params.get('is_active')
        if is_active is not None:
            queryset = queryset.filter(is_active=is_active.lower() == 'true')
        
        # Search
        search = self.request.query_params.get('search', '')
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) |
                Q(designation__icontains=search) |
                Q(description__icontains=search)
            )
        
        return queryset

    @action(detail=True, methods=['post'])
    def toggle_active(self, request, pk=None):
        """Toggle template active status"""
        template = self.get_object()
        template.is_active = not template.is_active
        template.save()
        serializer = self.get_serializer(template)
        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def apply_to_teachers(self, request, pk=None):
        """
        Apply template to multiple teachers
        Creates or updates TeacherPayStructure for selected teachers
        """
        template = self.get_object()
        teacher_ids = request.data.get('teacher_ids', [])
        
        if not teacher_ids:
            return Response(
                {"error": "teacher_ids list is required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        created = []
        updated = []
        errors = []
        
        for teacher_id in teacher_ids:
            try:
                teacher = Teacher.objects.get(id=teacher_id, is_active=True)
                
                # Check if pay structure already exists
                existing = TeacherPayStructure.objects.filter(
                    teacher=teacher,
                    is_active=True
                ).first()
                
                if existing:
                    # Update existing
                    existing.base_salary = template.base_salary
                    existing.dearness_allowance = template.dearness_allowance or 0
                    existing.house_rent_allowance = template.house_rent_allowance or 0
                    existing.city_compensatory_allowance = template.city_compensatory_allowance or 0
                    existing.travel_allowance = template.travel_allowance or 0
                    existing.medical_allowance = template.medical_allowance or 0
                    existing.special_allowance = template.special_allowance or 0
                    existing.education_allowance = template.education_allowance or 0
                    existing.telephone_allowance = template.telephone_allowance or 0
                    existing.provident_fund_percentage = template.provident_fund_percentage or 0
                    existing.esi_percentage = template.esi_percentage or 0
                    existing.professional_tax_fixed = template.professional_tax_fixed or 0
                    existing.effective_from = timezone.now().date()
                    existing.save()
                    updated.append({
                        "teacher_id": teacher_id,
                        "teacher_name": teacher.full_name
                    })
                else:
                    # Create new
                    pay_structure = TeacherPayStructure.objects.create(
                        teacher=teacher,
                        base_salary=template.base_salary,
                        dearness_allowance=template.dearness_allowance or 0,
                        house_rent_allowance=template.house_rent_allowance or 0,
                        city_compensatory_allowance=template.city_compensatory_allowance or 0,
                        travel_allowance=template.travel_allowance or 0,
                        medical_allowance=template.medical_allowance or 0,
                        special_allowance=template.special_allowance or 0,
                        education_allowance=template.education_allowance or 0,
                        telephone_allowance=template.telephone_allowance or 0,
                        provident_fund_percentage=template.provident_fund_percentage or 0,
                        esi_percentage=template.esi_percentage or 0,
                        professional_tax_fixed=template.professional_tax_fixed or 0,
                        effective_from=timezone.now().date(),
                        is_active=True,
                        created_by=request.user.teacher if hasattr(request.user, 'teacher') else None
                    )
                    created.append({
                        "teacher_id": teacher_id,
                        "teacher_name": teacher.full_name
                    })
                    
            except Teacher.DoesNotExist:
                errors.append({"teacher_id": teacher_id, "error": "Teacher not found"})
            except Exception as e:
                errors.append({"teacher_id": teacher_id, "error": str(e)})
        
        return Response({
            "success": True,
            "message": f"Applied template to {len(created)} new and {len(updated)} existing teachers",
            "created": created,
            "updated": updated,
            "errors": errors if errors else None
        })

    @action(detail=False, methods=['get'])
    def summary(self, request):
        """Get summary of all templates"""
        total_templates = self.get_queryset().count()
        active_templates = self.get_queryset().filter(is_active=True).count()
        inactive_templates = total_templates - active_templates
        
        # Templates by designation
        templates_by_designation = self.get_queryset().values('designation').annotate(
            count=Count('id')
        ).order_by('-count')
        
        return Response({
            "total_templates": total_templates,
            "active_templates": active_templates,
            "inactive_templates": inactive_templates,
            "by_designation": templates_by_designation
        })