# payslips/models.py

from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils import timezone
from people.models import Teacher

import logging
logger = logging.getLogger(__name__)


class TeacherPayStructure(models.Model):
    """
    Default/Base pay structure for a teacher
    This stores the teacher's permanent salary components
    Updated when teacher gets a raise or promotion
    """
    
    # Basic Information
    teacher = models.OneToOneField(
        Teacher, 
        on_delete=models.CASCADE, 
        related_name='pay_structure',
        help_text="Teacher this pay structure belongs to"
    )
    
    # Effective period
    effective_from = models.DateField(
        null=True, blank=True,
        help_text="Date from which this pay structure is effective"
    )
    effective_to = models.DateField(
        null=True, blank=True,
        help_text="Date until which this pay structure is valid (null = current)"
    )
    
    # =====================================================
    # Fixed Monthly Components (Default)
    # =====================================================
    
    # Basic Salary
    base_salary = models.DecimalField(
        max_digits=12, 
        decimal_places=2, 
        default=0.00,
        help_text="Base monthly salary"
    )
    
    # Allowances (Fixed monthly)
    dearness_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    house_rent_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    city_compensatory_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    travel_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    medical_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    special_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    education_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    telephone_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    
    # =====================================================
    # Fixed Monthly Deductions (Percentage based)
    # =====================================================
    
    provident_fund_percentage = models.DecimalField(
        max_digits=5, decimal_places=2, null=True, blank=True,
        help_text="PF percentage of base salary (e.g., 12%)"
    )
    esi_percentage = models.DecimalField(
        max_digits=5, decimal_places=2, null=True, blank=True,
        help_text="ESI percentage of base salary"
    )
    professional_tax_fixed = models.DecimalField(
        max_digits=10, decimal_places=2, null=True, blank=True, default=0.00,
        help_text="Fixed professional tax per month"
    )
    
    # =====================================================
    # Variable Components (that change month to month)
    # These are just defaults, actual values come from monthly adjustments
    # =====================================================
    
    default_performance_incentive = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    default_special_class_incentive = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    default_subject_expert_incentive = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    default_leadership_allowance = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True, default=0.00
    )
    
    # Status
    is_active = models.BooleanField(default=True)
    
    # Audit
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        Teacher, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='created_pay_structures'
    )
    
    class Meta:
        db_table = 'teacher_pay_structures'
        verbose_name = 'Teacher Pay Structure'
        verbose_name_plural = 'Teacher Pay Structures'
        ordering = ['-effective_from']
    
    def __str__(self):
        return f"{self.teacher.full_name} - Base: {self.base_salary} (from {self.effective_from})"
    
    @property
    def total_monthly_fixed_earnings(self):
        """Calculate total fixed monthly earnings"""
        total = self.base_salary
        total += self.dearness_allowance or 0
        total += self.house_rent_allowance or 0
        total += self.city_compensatory_allowance or 0
        total += self.travel_allowance or 0
        total += self.medical_allowance or 0
        total += self.special_allowance or 0
        total += self.education_allowance or 0
        total += self.telephone_allowance or 0
        return total


class MonthlyPaySlip(models.Model):
    """
    Monthly pay slip generated from TeacherPayStructure + monthly adjustments
    This is the actual salary for a specific month
    """
    
    STATUS_CHOICES = [
        ('DRAFT', 'Draft'),
        ('PENDING', 'Pending Approval'),
        ('APPROVED', 'Approved'),
        ('PAID', 'Paid'),
        ('CANCELLED', 'Cancelled'),
    ]
    
    # Basic Information
    teacher = models.ForeignKey(
        Teacher, 
        on_delete=models.CASCADE, 
        related_name='monthly_pay_slips'
    )
    pay_slip_number = models.CharField(max_length=100, unique=True)
    month = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(12)])
    year = models.PositiveIntegerField(validators=[MinValueValidator(2000), MaxValueValidator(2100)])
    
    # Reference to base pay structure (snapshot at time of generation)
    pay_structure_snapshot = models.JSONField(
        null=True, blank=True, default=dict,
        help_text="Snapshot of teacher's pay structure at generation time"
    )
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='DRAFT')
    
    # =====================================================
    # Fixed Components (from pay structure)
    # =====================================================
    base_salary = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    dearness_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    house_rent_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    city_compensatory_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    travel_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    medical_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    special_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    education_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    telephone_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    
    # =====================================================
    # Variable Components (Monthly Adjustments)
    # These override defaults or add extra for this month only
    # =====================================================
    
    # Additional earnings for this month
    performance_incentive = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    special_class_incentive = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    subject_expert_incentive = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    leadership_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    festival_bonus = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    annual_bonus = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    overtime_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    variable_pay = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    additional_earnings = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    
    # Other allowances (JSON for flexible entries)
    other_allowances = models.JSONField(null=True, blank=True, default=dict)
    
    # =====================================================
    # Deductions for this month
    # =====================================================
    provident_fund_employee = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    provident_fund_employer = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    esi_deduction = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    professional_tax = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    income_tax = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    loan_deduction = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    advance_deduction = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    attendance_deduction = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    
    # Other deductions (JSON for flexible entries)
    other_deductions = models.JSONField(null=True, blank=True, default=dict)
    
    # =====================================================
    # Leave and Attendance for this month
    # =====================================================
    casual_leave_taken = models.DecimalField(max_digits=5, decimal_places=1, null=True, blank=True, default=0.0)
    sick_leave_taken = models.DecimalField(max_digits=5, decimal_places=1, null=True, blank=True, default=0.0)
    earned_leave_taken = models.DecimalField(max_digits=5, decimal_places=1, null=True, blank=True, default=0.0)
    unpaid_leave_days = models.DecimalField(max_digits=5, decimal_places=1, null=True, blank=True, default=0.0)
    total_working_days = models.PositiveIntegerField(null=True, blank=True)
    days_present = models.PositiveIntegerField(null=True, blank=True)
    days_absent = models.PositiveIntegerField(null=True, blank=True)
    late_days = models.PositiveIntegerField(null=True, blank=True)
    
    # =====================================================
    # Calculated Totals
    # =====================================================
    total_earnings = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    total_deductions = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    net_pay = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    
    # =====================================================
    # Notes
    # =====================================================
    remarks = models.TextField(null=True, blank=True)
    hr_remarks = models.TextField(null=True, blank=True)
    
    # =====================================================
    # Approval Workflow
    # =====================================================
    created_by = models.ForeignKey(
        Teacher, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='created_pay_slips'
    )
    approved_by = models.ForeignKey(
        Teacher, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='approved_pay_slips'
    )
    approved_at = models.DateTimeField(null=True, blank=True)
    
    # Teacher acknowledgement
    is_acknowledged = models.BooleanField(default=False)
    acknowledged_at = models.DateTimeField(null=True, blank=True)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    
    class Meta:
        db_table = 'monthly_pay_slips'
        verbose_name = 'Monthly Pay Slip'
        verbose_name_plural = 'Monthly Pay Slips'
        ordering = ['-year', '-month']
        unique_together = ['teacher', 'month', 'year']
    
    def __str__(self):
        return f"{self.pay_slip_number} - {self.teacher.full_name} - {self.month}/{self.year}"
    
    def calculate_total_earnings(self):
        """Calculate total earnings"""
        earnings_fields = [
            'base_salary', 'dearness_allowance', 'house_rent_allowance',
            'city_compensatory_allowance', 'travel_allowance', 'medical_allowance',
            'special_allowance', 'education_allowance', 'telephone_allowance',
            'performance_incentive', 'special_class_incentive', 'subject_expert_incentive',
            'leadership_allowance', 'festival_bonus', 'annual_bonus',
            'overtime_allowance', 'variable_pay', 'additional_earnings'
        ]
        total = sum(float(getattr(self, f, 0) or 0) for f in earnings_fields)
        if self.other_allowances:
            total += sum(self.other_allowances.values())
        return total
    
    def calculate_total_deductions(self):
        """Calculate total deductions"""
        deductions_fields = [
            'provident_fund_employee', 'esi_deduction', 'professional_tax',
            'income_tax', 'loan_deduction', 'advance_deduction', 'attendance_deduction'
        ]
        total = sum(float(getattr(self, f, 0) or 0) for f in deductions_fields)
        if self.other_deductions:
            total += sum(self.other_deductions.values())
        return total
    
    def save(self, *args, **kwargs):
        if not self.pay_slip_number:
            self.pay_slip_number = f"PS-{self.year}-{self.month:02d}-{self.teacher.id}"
        self.total_earnings = self.calculate_total_earnings()
        self.total_deductions = self.calculate_total_deductions()
        self.net_pay = self.total_earnings - self.total_deductions
        super().save(*args, **kwargs)


class PaymentTransaction(models.Model):
    """
    Actual payment history - when salary is actually paid
    One MonthlyPaySlip can have multiple payment transactions
    (e.g., partial payment, advance, final payment)
    """
    
    PAYMENT_METHOD_CHOICES = [
        ('BANK_TRANSFER', 'Bank Transfer'),
        ('CASH', 'Cash'),
        ('CHEQUE', 'Cheque'),
        ('ONLINE', 'Online Payment'),
    ]
    
    PAYMENT_TYPE_CHOICES = [
        ('FULL', 'Full Payment'),
        ('PARTIAL', 'Partial Payment'),
        ('ADVANCE', 'Advance Payment'),
        ('BONUS', 'Bonus Payment'),
        ('REIMBURSEMENT', 'Reimbursement'),
    ]
    
    # Relationships
    pay_slip = models.ForeignKey(
        MonthlyPaySlip, 
        on_delete=models.CASCADE, 
        related_name='payment_transactions'
    )
    teacher = models.ForeignKey(
        Teacher, 
        on_delete=models.CASCADE, 
        related_name='payment_transactions'
    )
    
    # Payment Details
    payment_type = models.CharField(max_length=20, choices=PAYMENT_TYPE_CHOICES, default='FULL')
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHOD_CHOICES)
    payment_date = models.DateTimeField(default=timezone.now)
    
    # Transaction Details
    transaction_id = models.CharField(max_length=100, null=True, blank=True)
    bank_reference = models.CharField(max_length=100, null=True, blank=True)
    cheque_number = models.CharField(max_length=50, null=True, blank=True)
    upi_id = models.CharField(max_length=100, null=True, blank=True)
    
    # Bank Details (for this transaction)
    bank_name = models.CharField(max_length=255, null=True, blank=True)
    bank_account_number = models.CharField(max_length=50, null=True, blank=True)
    bank_ifsc_code = models.CharField(max_length=20, null=True, blank=True)
    
    # Status
    status = models.CharField(
        max_length=20,
        choices=[('PENDING', 'Pending'), ('COMPLETED', 'Completed'), ('FAILED', 'Failed'), ('REFUNDED', 'Refunded')],
        default='PENDING'
    )
    
    # Notes
    remarks = models.TextField(null=True, blank=True)
    
    # Recorded by
    recorded_by = models.ForeignKey(
        Teacher, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='recorded_payments'
    )
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'payment_transactions'
        verbose_name = 'Payment Transaction'
        verbose_name_plural = 'Payment Transactions'
        ordering = ['-payment_date']
    
    def __str__(self):
        return f"{self.pay_slip.pay_slip_number} - {self.payment_type} - {self.amount}"


class PaySlipTemplate(models.Model):
    """
    Template for generating monthly pay slips
    Can be applied to multiple teachers
    """
    
    name = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)
    
    # Which teachers this template applies to (null = all teachers)
    applicable_teachers = models.ManyToManyField(
        Teacher, blank=True, related_name='pay_slip_templates'
    )
    
    # Designation filter
    designation = models.CharField(max_length=255, null=True, blank=True)
    
    # =====================================================
    # Template Components (same structure as TeacherPayStructure)
    # =====================================================
    base_salary = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    dearness_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    house_rent_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    city_compensatory_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    travel_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    medical_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    special_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    education_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    telephone_allowance = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True, default=0.00)
    
    # Deductions percentage
    provident_fund_percentage = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
    esi_percentage = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
    professional_tax_fixed = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, default=0.00)
    
    # Status
    is_active = models.BooleanField(default=True)
    
    # Audit
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        Teacher, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='created_pay_templates'
    )
    
    class Meta:
        db_table = 'pay_slip_templates'
        verbose_name = 'Pay Slip Template'
        verbose_name_plural = 'Pay Slip Templates'
    
    def __str__(self):
        return self.name