# =====================================================
# TEACHER PAYSLIP VIEWS
# =====================================================

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db.models import Q, Sum, Count, Avg, F
from django.utils import timezone
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from datetime import datetime, timedelta

from people.models import Teacher
from payslips.models import MonthlyPaySlip, PaymentTransaction, TeacherPayStructure
from .teacher_payslip_serializers import (
    TeacherPaySlipListSerializer,
    TeacherPaySlipDetailSerializer,
    TeacherPaySlipSummarySerializer,
    TeacherCurrentPayStructureSerializer,
    TeacherPaymentTransactionSerializer,
)

import logging

logger = logging.getLogger(__name__)

class TeacherMyPaySlipsView(APIView):
    """
    GET /teacher/payslips/
    
    Get all pay slips for the logged-in teacher with lazy loading pagination.
    
    Query Parameters:
    - year (optional) - filter by year
    - month (optional) - filter by month
    - status (optional) - DRAFT, PENDING, APPROVED, PAID, CANCELLED
    - page (optional, default=1) - page number for traditional pagination
    - page_size (optional, default=10)
    - cursor (optional) - for cursor-based pagination (id of last item)
    - limit (optional, default=10) - number of items per page for cursor pagination
    - pagination_type (optional) - 'page' or 'cursor' (default: 'page')
    """
    
    permission_classes = [IsAuthenticated]
    
    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            current_date = timezone.now()
            
            # Get query parameters
            year = request.query_params.get('year')
            month = request.query_params.get('month')
            status_filter = request.query_params.get('status')
            pagination_type = request.query_params.get('pagination_type', 'page')
            
            # Store applied filters for response
            applied_year = year
            applied_month = month
            applied_status = status_filter
            
            # Base queryset
            pay_slips = MonthlyPaySlip.objects.filter(
                teacher=teacher,
                is_active=True
            ).order_by('-year', '-month', '-id')
            
            # Apply filters - default to current year if not specified
            if year:
                pay_slips = pay_slips.filter(year=year)
            else:
                # Default to current year
                pay_slips = pay_slips.filter(year=current_date.year)
                applied_year = str(current_date.year)
            
            if month:
                pay_slips = pay_slips.filter(month=month)
                applied_month = month
            
            if status_filter:
                pay_slips = pay_slips.filter(status=status_filter.upper())
                applied_status = status_filter.upper()
            
            # Get available years for filter dropdown
            available_years = MonthlyPaySlip.objects.filter(
                teacher=teacher,
                is_active=True
            ).values_list('year', flat=True).distinct().order_by('-year')
            
            if not available_years:
                available_years = [current_date.year]
            
            # Get status counts for summary (using filtered queryset)
            status_counts = {
                'DRAFT': pay_slips.filter(status='DRAFT').count(),
                'PENDING': pay_slips.filter(status='PENDING').count(),
                'APPROVED': pay_slips.filter(status='APPROVED').count(),
                'PAID': pay_slips.filter(status='PAID').count(),
                'CANCELLED': pay_slips.filter(status='CANCELLED').count(),
                'TOTAL': pay_slips.count(),
            }
            
            # Calculate total earned amount (APPROVED + PAID)
            total_earned = pay_slips.filter(
                status__in=['APPROVED', 'PAID']
            ).aggregate(total=Sum('net_pay'))['total'] or 0
            
            # Calculate total paid amount (actual payments made)
            total_paid_actual = PaymentTransaction.objects.filter(
                pay_slip__teacher=teacher,
                status='COMPLETED'
            ).aggregate(total=Sum('amount'))['total'] or 0
            
            # ============================================================
            # PAGINATION
            # ============================================================
            
            if pagination_type == 'cursor':
                # Cursor-based pagination for lazy loading
                cursor = request.query_params.get('cursor')
                limit = int(request.query_params.get('limit', 10))
                
                if cursor:
                    # Get items after the cursor
                    try:
                        last_id = int(cursor)
                        pay_slips = pay_slips.filter(id__lt=last_id)
                    except ValueError:
                        pass
                
                # Get one extra item to check if there are more
                paginated_items = list(pay_slips[:limit + 1])
                has_next = len(paginated_items) > limit
                items = paginated_items[:limit]
                
                # Get next cursor
                next_cursor = items[-1].id if has_next and items else None
                
                # Serialize data
                serializer = TeacherPaySlipListSerializer(items, many=True)
                
                pagination_data = {
                    "type": "cursor",
                    "limit": limit,
                    "has_next": has_next,
                    "next_cursor": next_cursor,
                    "current_item_count": len(items)
                }
                
            else:
                # Traditional page-based pagination
                page = int(request.query_params.get('page', 1))
                page_size = int(request.query_params.get('page_size', 10))
                
                paginator = Paginator(pay_slips, page_size)
                try:
                    paginated_pay_slips = paginator.page(page)
                except PageNotAnInteger:
                    paginated_pay_slips = paginator.page(1)
                except EmptyPage:
                    paginated_pay_slips = paginator.page(paginator.num_pages)
                
                # Serialize data
                serializer = TeacherPaySlipListSerializer(paginated_pay_slips, many=True)
                
                pagination_data = {
                    "type": "page",
                    "current_page": paginated_pay_slips.number,
                    "total_pages": paginator.num_pages,
                    "total_items": paginator.count,
                    "page_size": page_size,
                    "has_next": paginated_pay_slips.has_next(),
                    "has_previous": paginated_pay_slips.has_previous(),
                    "next_page": paginated_pay_slips.next_page_number() if paginated_pay_slips.has_next() else None,
                    "previous_page": paginated_pay_slips.previous_page_number() if paginated_pay_slips.has_previous() else None
                }
            
            return Response({
                "success": True,
                "data": {
                    "pay_slips": serializer.data,
                    "summary": {
                        "total_pay_slips": status_counts['TOTAL'],
                        "draft_count": status_counts['DRAFT'],
                        "pending_count": status_counts['PENDING'],
                        "approved_count": status_counts['APPROVED'],
                        "paid_count": status_counts['PAID'],
                        "cancelled_count": status_counts['CANCELLED'],
                        "total_earned": float(total_earned),
                        "total_paid": float(total_paid_actual)
                    },
                    "filters": {
                        "available_years": list(available_years),
                        "current_year": applied_year,
                        "current_month": applied_month,
                        "current_status": applied_status
                    },
                    "pagination": pagination_data
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherMyPaySlipsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
            
class TeacherPaySlipDetailView(APIView):
    """
    GET /teacher/payslips/<pay_slip_id>/

    Get detailed information of a specific pay slip.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, pay_slip_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get pay slip and verify ownership
            pay_slip = MonthlyPaySlip.objects.filter(
                id=pay_slip_id, teacher=teacher, is_active=True
            ).first()

            if not pay_slip:
                return Response(
                    {"success": False, "message": "Pay slip not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            serializer = TeacherPaySlipDetailSerializer(pay_slip)

            return Response({"success": True, "data": serializer.data})

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherPaySlipDetailView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherPaySlipSummaryView(APIView):
    """
    GET /teacher/payslips/summary/

    Get annual summary of pay slips for the logged-in teacher.

    Query Parameters:
    - year (optional, defaults to current year)
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get year parameter
            year = request.query_params.get("year", datetime.now().year)
            try:
                year = int(year)
            except ValueError:
                year = datetime.now().year

            # Get all pay slips for the year
            pay_slips = MonthlyPaySlip.objects.filter(
                teacher=teacher, year=year, is_active=True
            ).order_by("month")

            # Calculate totals
            total_earned = (
                pay_slips.filter(status="PAID").aggregate(total=Sum("net_pay"))["total"]
                or 0
            )

            total_deductions = (
                pay_slips.aggregate(total=Sum("total_deductions"))["total"] or 0
            )

            # Calculate average monthly
            paid_months = pay_slips.filter(status="PAID").count()
            average_monthly = total_earned / paid_months if paid_months > 0 else 0

            # Find best and worst month (by net pay)
            monthly_data = []
            best_month = None
            worst_month = None
            best_net = -1
            worst_net = float("inf")

            for month in range(1, 13):
                pay_slip = pay_slips.filter(month=month).first()
                if pay_slip:
                    month_data = {
                        "month": month,
                        "month_name": self._get_month_name(month),
                        "net_pay": float(pay_slip.net_pay),
                        "status": pay_slip.status,
                        "pay_slip_number": pay_slip.pay_slip_number,
                    }
                    monthly_data.append(month_data)

                    if pay_slip.status == "PAID":
                        net = float(pay_slip.net_pay)
                        if net > best_net:
                            best_net = net
                            best_month = month_data
                        if net < worst_net:
                            worst_net = net
                            worst_month = month_data
                else:
                    monthly_data.append(
                        {
                            "month": month,
                            "month_name": self._get_month_name(month),
                            "net_pay": 0,
                            "status": "NOT_GENERATED",
                            "pay_slip_number": None,
                        }
                    )

            # Yearly breakdown by status
            yearly_breakdown = []
            for status_choice in ["DRAFT", "PENDING", "APPROVED", "PAID", "CANCELLED"]:
                count = pay_slips.filter(status=status_choice).count()
                if count > 0:
                    total = (
                        pay_slips.filter(status=status_choice).aggregate(
                            total=Sum("net_pay")
                        )["total"]
                        or 0
                    )
                    yearly_breakdown.append(
                        {
                            "status": status_choice,
                            "count": count,
                            "total_amount": float(total),
                        }
                    )

            return Response(
                {
                    "success": True,
                    "data": {
                        "year": year,
                        "total_pay_slips": pay_slips.count(),
                        "total_earned": float(total_earned),
                        "total_deductions": float(total_deductions),
                        "average_monthly": round(float(average_monthly), 2),
                        "best_month": best_month,
                        "worst_month": worst_month,
                        "yearly_breakdown": yearly_breakdown,
                        "monthly_data": monthly_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherPaySlipSummaryView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_month_name(self, month):
        months = [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December",
        ]
        return months[month - 1] if 1 <= month <= 12 else str(month)


class TeacherCurrentPayStructureView(APIView):
    """
    GET /teacher/payslips/current-pay-structure/

    Get current active pay structure for the logged-in teacher.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get current active pay structure
            pay_structure = TeacherPayStructure.objects.filter(
                teacher=teacher, is_active=True
            ).first()

            if not pay_structure:
                return Response(
                    {
                        "success": True,
                        "data": None,
                        "message": "No active pay structure found for this teacher",
                    }
                )

            serializer = TeacherCurrentPayStructureSerializer(pay_structure)

            return Response({"success": True, "data": serializer.data})

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherCurrentPayStructureView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherAcknowledgePaySlipView(APIView):
    """
    POST /teacher/payslips/<pay_slip_id>/acknowledge/

    Teacher acknowledges receipt of pay slip.
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, pay_slip_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get pay slip and verify ownership
            pay_slip = MonthlyPaySlip.objects.filter(
                id=pay_slip_id, teacher=teacher, is_active=True
            ).first()

            if not pay_slip:
                return Response(
                    {"success": False, "message": "Pay slip not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if pay_slip.status != "PAID":
                return Response(
                    {
                        "success": False,
                        "message": f"Pay slip must be paid before acknowledgement. Current status: {pay_slip.status}",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if pay_slip.is_acknowledged:
                return Response(
                    {"success": False, "message": "Pay slip already acknowledged"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update acknowledgement
            pay_slip.is_acknowledged = True
            pay_slip.acknowledged_at = timezone.now()
            pay_slip.save(update_fields=["is_acknowledged", "acknowledged_at"])

            return Response(
                {
                    "success": True,
                    "message": "Pay slip acknowledged successfully",
                    "data": {
                        "pay_slip_id": pay_slip.id,
                        "pay_slip_number": pay_slip.pay_slip_number,
                        "is_acknowledged": pay_slip.is_acknowledged,
                        "acknowledged_at": pay_slip.acknowledged_at,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherAcknowledgePaySlipView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherDownloadPaySlipView(APIView):
    """
    GET /teacher/payslips/<pay_slip_id>/download/

    Get pay slip data for download/print.
    (Returns HTML/JSON representation for PDF generation)
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, pay_slip_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get pay slip and verify ownership
            pay_slip = MonthlyPaySlip.objects.filter(
                id=pay_slip_id, teacher=teacher, is_active=True
            ).first()

            if not pay_slip:
                return Response(
                    {"success": False, "message": "Pay slip not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get payment transactions
            payments = pay_slip.payment_transactions.filter(
                status="COMPLETED"
            ).order_by("-payment_date")

            # Calculate totals
            total_paid = payments.aggregate(total=Sum("amount"))["total"] or 0

            # Get teacher details
            teacher_details = {
                "full_name": teacher.full_name,
                "employee_id": teacher.employee_id,
                "email": teacher.email,
                "phone": teacher.phone,
                "bank_account_number": (
                    teacher.bank_account_number
                    if hasattr(teacher, "bank_account_number")
                    else None
                ),
                "bank_name": (
                    teacher.bank_name if hasattr(teacher, "bank_name") else None
                ),
                "pan_number": (
                    teacher.identification_number
                    if hasattr(teacher, "identification_number")
                    else None
                ),
            }

            # Get school name from request context (set by SchoolContextMiddleware)
            school = getattr(request, 'school', None)
            school_name = school.name if school else 'School'

            # Build download data
            download_data = {
                "school_name": school_name,
                "pay_slip": {
                    "pay_slip_number": pay_slip.pay_slip_number,
                    "month": self._get_month_name(pay_slip.month),
                    "year": pay_slip.year,
                    "status": pay_slip.status,
                    "generated_date": pay_slip.created_at.strftime("%d %B %Y"),
                    "payment_date": (
                        payments.first().payment_date.strftime("%d %B %Y")
                        if payments.first()
                        else None
                    ),
                },
                "teacher": teacher_details,
                "earnings": {
                    "base_salary": float(pay_slip.base_salary),
                    "dearness_allowance": float(pay_slip.dearness_allowance or 0),
                    "house_rent_allowance": float(pay_slip.house_rent_allowance or 0),
                    "city_compensatory_allowance": float(
                        pay_slip.city_compensatory_allowance or 0
                    ),
                    "travel_allowance": float(pay_slip.travel_allowance or 0),
                    "medical_allowance": float(pay_slip.medical_allowance or 0),
                    "special_allowance": float(pay_slip.special_allowance or 0),
                    "education_allowance": float(pay_slip.education_allowance or 0),
                    "telephone_allowance": float(pay_slip.telephone_allowance or 0),
                    "performance_incentive": float(pay_slip.performance_incentive or 0),
                    "special_class_incentive": float(
                        pay_slip.special_class_incentive or 0
                    ),
                    "subject_expert_incentive": float(
                        pay_slip.subject_expert_incentive or 0
                    ),
                    "leadership_allowance": float(pay_slip.leadership_allowance or 0),
                    "festival_bonus": float(pay_slip.festival_bonus or 0),
                    "annual_bonus": float(pay_slip.annual_bonus or 0),
                    "overtime_allowance": float(pay_slip.overtime_allowance or 0),
                    "variable_pay": float(pay_slip.variable_pay or 0),
                    "additional_earnings": float(pay_slip.additional_earnings or 0),
                    "total_earnings": float(pay_slip.total_earnings),
                },
                "deductions": {
                    "provident_fund": float(pay_slip.provident_fund_employee or 0),
                    "esi_deduction": float(pay_slip.esi_deduction or 0),
                    "professional_tax": float(pay_slip.professional_tax or 0),
                    "income_tax": float(pay_slip.income_tax or 0),
                    "loan_deduction": float(pay_slip.loan_deduction or 0),
                    "advance_deduction": float(pay_slip.advance_deduction or 0),
                    "attendance_deduction": float(pay_slip.attendance_deduction or 0),
                    "total_deductions": float(pay_slip.total_deductions),
                },
                "net_pay": float(pay_slip.net_pay),
                "total_paid": float(total_paid),
                "remaining_balance": float(pay_slip.net_pay) - float(total_paid),
                "payments": [
                    {
                        "amount": float(p.amount),
                        "payment_date": p.payment_date.strftime("%d %B %Y"),
                        "payment_method": p.get_payment_method_display(),
                        "transaction_id": p.transaction_id,
                        "remarks": p.remarks,
                    }
                    for p in payments
                ],
                "leave_details": {
                    "casual_leave_taken": float(pay_slip.casual_leave_taken or 0),
                    "sick_leave_taken": float(pay_slip.sick_leave_taken or 0),
                    "earned_leave_taken": float(pay_slip.earned_leave_taken or 0),
                    "unpaid_leave_days": float(pay_slip.unpaid_leave_days or 0),
                    "total_working_days": pay_slip.total_working_days,
                    "days_present": pay_slip.days_present,
                    "days_absent": pay_slip.days_absent,
                    "late_days": pay_slip.late_days,
                },
            }

            return Response({"success": True, "data": download_data})

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherDownloadPaySlipView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_month_name(self, month):
        months = [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December",
        ]
        return months[month - 1] if 1 <= month <= 12 else str(month)
