# staff/models.py
"""
Staff management models for teachers, administrators, and support staff.
"""
from django.db import models
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
from core.models import School

User = get_user_model()


class Staff(models.Model):
    """
    Complete Staff Model for Rapha-Bethel BNPS.
    
    This model extends the user model with staff-specific information including
    employment details, qualifications, contact information, and role-based
    assignments. It handles all staff types from teachers to support staff.
    
    Attributes:
        user (OneToOneField): Link to the Django user account
        school (ForeignKey): School this staff member belongs to
        employee_id (str): Unique staff identifier
        date_of_birth (date): Staff member's birth date
        gender (str): Gender from GENDER_CHOICES
        nationality (str): Staff member's nationality
        marital_status (str): Marital status
        phone_number (str): Primary contact number
        alternate_phone (str): Secondary contact number
        email (str): Email address
        address (str): Residential address
        quarter (str): Neighborhood/district
        city (str): City of residence
        emergency_contact_name (str): Name of emergency contact
        emergency_contact_phone (str): Emergency contact number
        emergency_contact_relationship (str): Relationship to emergency contact
        role (str): Staff role from ROLE_CHOICES
        department (str): Department from DEPARTMENT_CHOICES
        employment_status (str): Current employment status
        hire_date (date): Date of employment start
        contract_end_date (date): End of contract date
        qualifications (str): Educational and professional qualifications
        specialization (str): Area of specialization
        years_of_experience (int): Total years of experience
        subjects_taught (ManyToManyField): Subjects this teacher teaches
        is_class_teacher (bool): Whether staff is a class teacher
        homeroom_class (ForeignKey): Class this teacher is responsible for
        salary (Decimal): Monthly salary in XAF
        bank_name (str): Bank name for salary deposits
        bank_account (str): Bank account number
        bank_branch (str): Bank branch location
        tax_id (str): Tax identification number
        social_security (str): Social security number
        photo (ImageField): Staff profile photo
        cv_file (FileField): CV/resume document
        contract_file (FileField): Employment contract
        id_document (FileField): ID document
        diplomas (FileField): Diplomas and certificates
        created_at (datetime): When record was created
        updated_at (datetime): When record was last updated
        is_active (bool): Whether staff is currently active
        notes (str): Additional notes
        imported_from (str): Source of import if applicable
        original_data (JSONField): Original imported data
    """
    
    # Role Choices based on your Excel data
    ROLE_CHOICES = [
        ('proprietor', 'Proprietor'),
        ('head_master', 'Head Master'),
        ('head_mistress', 'Head Mistress'),
        ('bursar', 'Bursar'),
        ('admin', 'Administrator'),
        ('teacher', 'Teacher'),
        ('class_teacher', 'Class Teacher'),
        ('subject_teacher', 'Subject Teacher'),
        ('assistant_teacher', 'Assistant Teacher'),
        ('secretary', 'Secretary'),
        ('driver', 'Driver'),
        ('cleaner', 'Cleaner'),
        ('canteen', 'Canteen Staff'),
        ('security', 'Security'),
        ('support', 'Support Staff'),
        ('other', 'Other'),
    ]
    
    # Department Choices
    DEPARTMENT_CHOICES = [
        ('admin', 'Administration'),
        ('english', 'English Section'),
        ('french', 'French Section'),
        ('bilingual', 'Bilingual Section'),
        ('nursery', 'Nursery Section'),
        ('finance', 'Finance'),
        ('support', 'Support Staff'),
        ('transport', 'Transport'),
    ]
    
    # Employment Status
    EMPLOYMENT_STATUS = [
        ('permanent', 'Permanent'),
        ('contract', 'Contract'),
        ('probation', 'Probation'),
        ('intern', 'Intern'),
        ('volunteer', 'Volunteer'),
        ('part_time', 'Part Time'),
        ('casual', 'Casual'),
    ]
    
    # Gender Choices
    GENDER_CHOICES = [
        ('M', 'Male'),
        ('F', 'Female'),
        ('O', 'Other'),
    ]
    
    # Title / Honorific choices
    TITLE_CHOICES = [
        ('', '—'),
        ('Mr', 'Mr'),
        ('Mrs', 'Mrs'),
        ('Mme', 'Mme'),
        ('Ms', 'Ms'),
        ('Dr', 'Dr'),
        ('Prof', 'Prof'),
        ('Rev', 'Rev'),
        ('Sis', 'Sis'),
    ]

    # Phone number: accepts local format (e.g. 670177979) — no +237 required.
    # Country code is stored separately in phone_country_code.
    phone_regex = RegexValidator(
        regex=r'^\d{6,15}$',
        message="Enter digits only, e.g. 670177979 — no spaces, dashes, or country code"
    )

    # Country code dropdown choices
    COUNTRY_CODE_CHOICES = [
        ('+237', '+237 \U0001f1e8\U0001f1f2 Cameroon'),
        ('+234', '+234 \U0001f1f3\U0001f1ec Nigeria'),
        ('+241', '+241 \U0001f1ec\U0001f1e6 Gabon'),
        ('+242', '+242 \U0001f1e8\U0001f1ec Congo-Brazzaville'),
        ('+243', '+243 \U0001f1e8\U0001f1e9 DR Congo'),
        ('+225', '+225 \U0001f1e8\U0001f1ee Cote d\'Ivoire'),
        ('+233', '+233 \U0001f1ec\U0001f1ed Ghana'),
        ('+221', '+221 \U0001f1f8\U0001f1f3 Senegal'),
        ('+44',  '+44  \U0001f1ec\U0001f1e7 UK'),
        ('+33',  '+33  \U0001f1eb\U0001f1f7 France'),
        ('+1',   '+1   \U0001f1fa\U0001f1f8 US/Canada'),
    ]
    
    # ========== USER LINK ==========
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='staff_profile',
        verbose_name=_("User Account")
    )
    
    school = models.ForeignKey(
        School,
        on_delete=models.CASCADE,
        related_name='staff_members',
        default=1,
        verbose_name=_("School")
    )
    
    # ========== PERSONAL INFORMATION ==========
    employee_id = models.CharField(
        max_length=20,
        unique=True,
        verbose_name=_("Employee ID"),
        help_text=_("Unique staff identifier")
    )

    title = models.CharField(
        max_length=10,
        choices=TITLE_CHOICES,
        blank=True,
        default='',
        verbose_name=_("Title/Honorific"),
        help_text=_("e.g. Mr, Mme, Dr — do NOT put this in First Name")
    )

    date_of_birth = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Date of Birth")
    )
    
    gender = models.CharField(
        max_length=1,
        choices=GENDER_CHOICES,
        default='M',
        verbose_name=_("Gender")
    )
    
    nationality = models.CharField(
        max_length=50,
        default="Cameroonian",
        blank=True,
        verbose_name=_("Nationality")
    )
    
    marital_status = models.CharField(
        max_length=20,
        choices=[
            ('single', 'Single'),
            ('married', 'Married'),
            ('divorced', 'Divorced'),
            ('widowed', 'Widowed'),
        ],
        default='single',
        blank=True,
        verbose_name=_("Marital Status")
    )
    
    # ========== CONTACT INFORMATION ==========
    phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Country Code")
    )
    phone_number = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Phone Number"),
        help_text=_("Local digits only, e.g. 670177979")
    )

    alt_phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Alt. Country Code")
    )
    alternate_phone = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Alternate Phone Number"),
        help_text=_("Local digits only")
    )

    email = models.EmailField(
        blank=True,
        verbose_name=_("Email Address")
    )

    address = models.TextField(
        blank=True,
        verbose_name=_("Residential Address")
    )

    quarter = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Quarter/Neighborhood"),
        help_text=_("e.g., Bonapriso, Akwa, Bonanjo")
    )

    city = models.CharField(
        max_length=100,
        default="Douala",
        blank=True,
        verbose_name=_("City")
    )

    # ========== EMERGENCY CONTACT ==========
    emergency_contact_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Emergency Contact Name")
    )

    emergency_phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Emergency Country Code")
    )
    emergency_contact_phone = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Emergency Contact Phone"),
        help_text=_("Local digits only")
    )

    emergency_contact_relationship = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Relationship")
    )
    
    # ========== EMPLOYMENT DETAILS ==========
    role = models.CharField(
        max_length=20,
        choices=ROLE_CHOICES,
        default='teacher',
        verbose_name=_("Role/Position")
    )
    
    department = models.CharField(
        max_length=20,
        choices=DEPARTMENT_CHOICES,
        default='english',
        verbose_name=_("Department")
    )
    
    employment_status = models.CharField(
        max_length=20,
        choices=EMPLOYMENT_STATUS,
        default='contract',
        verbose_name=_("Employment Status")
    )
    
    hire_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Hire Date")
    )
    
    contract_end_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Contract End Date")
    )
    
    # ========== QUALIFICATIONS ==========
    qualifications = models.TextField(
        blank=True,
        verbose_name=_("Qualifications"),
        help_text=_("Degrees, certifications, training")
    )
    
    specialization = models.CharField(
        max_length=200,
        blank=True,
        verbose_name=_("Specialization"),
        help_text=_("Subject area specialization")
    )
    
    years_of_experience = models.PositiveIntegerField(
        default=0,
        verbose_name=_("Years of Experience")
    )
    
    # ========== TEACHER-SPECIFIC FIELDS ==========
    subjects_taught = models.ManyToManyField(
        'academics.Subject',
        through='TeacherSubject',
        blank=True,
        related_name='teachers',
        verbose_name=_("Subjects Taught")
    )
    
    is_class_teacher = models.BooleanField(
        default=False,
        verbose_name=_("Is Class Teacher?")
    )
    
    homeroom_class = models.ForeignKey(
        'academics.SchoolClass',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='homeroom_teachers',
        verbose_name=_("Homeroom Class")
    )
    
    # ========== FINANCIAL INFORMATION ==========
    salary = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        null=True,
        blank=True,
        verbose_name=_("Monthly Salary (XAF)")
    )
    
    bank_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Bank Name")
    )
    
    bank_account = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Bank Account Number")
    )
    
    bank_branch = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Bank Branch")
    )
    
    tax_id = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Tax ID / NIU")
    )
    
    social_security = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Social Security Number")
    )
    
    # ========== DOCUMENTS ==========
    photo = models.ImageField(
        upload_to='staff/photos/',
        null=True,
        blank=True,
        verbose_name=_("Profile Photo")
    )
    
    cv_file = models.FileField(
        upload_to='staff/documents/cv/',
        null=True,
        blank=True,
        verbose_name=_("CV/Resume")
    )
    
    contract_file = models.FileField(
        upload_to='staff/documents/contracts/',
        null=True,
        blank=True,
        verbose_name=_("Employment Contract")
    )
    
    id_document = models.FileField(
        upload_to='staff/documents/id/',
        null=True,
        blank=True,
        verbose_name=_("ID Document")
    )
    
    diplomas = models.FileField(
        upload_to='staff/documents/diplomas/',
        null=True,
        blank=True,
        verbose_name=_("Diplomas/Certificates")
    )
    
    # ========== SYSTEM FIELDS ==========
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Created At")
    )
    
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At")
    )
    
    is_active = models.BooleanField(
        default=True,
        verbose_name=_("Active")
    )
    
    notes = models.TextField(
        blank=True,
        verbose_name=_("Additional Notes")
    )
    
    # ========== IMPORT TRACKING ==========
    imported_from = models.CharField(
        max_length=100,
        blank=True,
        help_text="Source of import (e.g., 'Staff Excel')"
    )
    
    original_data = models.JSONField(
        null=True,
        blank=True,
        help_text="Original imported data"
    )
    
    class Meta:
        verbose_name = "Staff Member"
        verbose_name_plural = "Staff Members"
        ordering = ['employee_id','role', 'user__first_name', 'user__last_name']
        indexes = [
            models.Index(fields=['employee_id']),
            models.Index(fields=['role']),
            models.Index(fields=['department']),
            models.Index(fields=['is_active']),
        ]
    
    def __str__(self):
        """Return string representation of the staff member."""
        name = self.get_display_name() or self.user.get_full_name()
        return f"{name} - {self.get_role_display()} ({self.employee_id})"

    def get_full_name(self):
        """
        Get the display name including title.

        Returns:
            str: Title + first + last name, e.g. 'Mme Annie Shey'.
        """
        return self.get_display_name() or self.user.get_full_name()
    
    def save(self, *args, **kwargs):
        """
        Save the staff member with auto-generated employee ID.
        
        Generates a unique employee ID based on role prefix if not provided.
        """
        if not self.employee_id:
            prefix = {
                'proprietor': 'PR',
                'head_master': 'HM',
                'head_mistress': 'HM',
                'bursar': 'BR',
                'teacher': 'TCH',
                'class_teacher': 'CT',
                'subject_teacher': 'ST',
                'driver': 'DR',
                'cleaner': 'CL',
            }.get(self.role, 'STF')
            
            last_staff = Staff.objects.filter(employee_id__startswith=prefix).order_by('-id').first()
            if last_staff:
                last_num = int(last_staff.employee_id.split('-')[-1]) if '-' in last_staff.employee_id else 1
                new_num = last_num + 1
            else:
                new_num = 1
            self.employee_id = f"{prefix}-{new_num:04d}"
        
        super().save(*args, **kwargs)
    
    @property
    def is_teacher(self):
        """
        Check if staff member is a teacher.
        
        Returns:
            bool: True if role is teacher-related.
        """
        return self.role in ['teacher', 'class_teacher', 'subject_teacher', 'assistant_teacher']
    
    @property
    def is_admin(self):
        """
        Check if staff member is in administration.
        
        Returns:
            bool: True if role is administrative.
        """
        return self.role in ['proprietor', 'head_master', 'head_mistress', 'bursar', 'admin']
    
    @property
    def is_support(self):
        """
        Check if staff member is support staff.
        
        Returns:
            bool: True if role is support-related.
        """
        return self.role in ['driver', 'cleaner', 'canteen', 'security', 'support']
    
    def get_full_phone(self, which='primary'):
        """Return formatted phone number with country code."""
        if which == 'primary':
            code, num = self.phone_country_code, self.phone_number
        elif which == 'alternate':
            code, num = self.alt_phone_country_code, self.alternate_phone
        else:
            code, num = self.emergency_phone_country_code, self.emergency_contact_phone
        return f"{code} {num}" if num else ""

    def get_display_name(self):
        """Return title + full name, e.g. 'Mme Annie Shey'."""
        parts = [self.title, self.user.first_name, self.user.last_name]
        return " ".join(p for p in parts if p).strip()

    def get_contact_info(self):
        """
        Get formatted contact information.

        Returns:
            str: Formatted string with phone and email information.
        """
        info = []
        if self.phone_number:
            info.append(f"📞 {self.get_full_phone('primary')}")
        if self.alternate_phone:
            info.append(f"📱 {self.get_full_phone('alternate')}")
        if self.email:
            info.append(f"📧 {self.email}")
        return " | ".join(info) if info else "No contact info"


class TeacherSubject(models.Model):
    """
    Junction model for teachers and subjects with class assignments.
    
    This model tracks which teacher teaches which subject, optionally
    in a specific class with hours per week.
    
    Attributes:
        teacher (ForeignKey): Teacher assigned
        subject (ForeignKey): Subject being taught
        class_assigned (ForeignKey): Specific class (optional)
        hours_per_week (int): Hours allocated weekly
    """
    
    teacher = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='teacher_subjects'
    )
    subject = models.ForeignKey(
        'academics.Subject', 
        on_delete=models.CASCADE, 
        related_name='subject_teachers'
    )
    class_assigned = models.ForeignKey(
        'academics.SchoolClass', 
        on_delete=models.CASCADE, 
        null=True, 
        blank=True
    )
    hours_per_week = models.PositiveIntegerField(
        default=2
    )
    
    class Meta:
        unique_together = ['teacher', 'subject', 'class_assigned']
        verbose_name = "Teacher Subject Assignment"
        verbose_name_plural = "Teacher Subject Assignments"
    
    def __str__(self):
        """Return string representation of the assignment."""
        return f"{self.teacher} - {self.subject}"


class StaffAttendance(models.Model):
    """
    Tracks daily attendance for staff members.
    
    Separate from student attendance, this model records when staff
    check in and out, their attendance status, and any remarks.
    
    Attributes:
        staff (ForeignKey): Staff member
        date (date): Date of attendance
        check_in_time (time): Time staff checked in
        check_out_time (time): Time staff checked out
        status (str): Attendance status from STATUS_CHOICES
        remarks (str): Additional notes
    """
    
    STATUS_CHOICES = [
        ('present', 'Present'),
        ('absent', 'Absent'),
        ('late', 'Late'),
        ('leave', 'On Leave'),
        ('sick', 'Sick Leave'),
        ('training', 'Training'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    date = models.DateField()
    check_in_time = models.TimeField(
        null=True, 
        blank=True
    )
    check_out_time = models.TimeField(
        null=True, 
        blank=True
    )
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='present'
    )
    remarks = models.CharField(
        max_length=200, 
        blank=True
    )
    
    class Meta:
        unique_together = ['staff', 'date']
        ordering = ['-date']
        verbose_name = "Staff Attendance"
        verbose_name_plural = "Staff Attendances"
    
    def __str__(self):
        """Return string representation of staff attendance."""
        return f"{self.staff} - {self.date} - {self.get_status_display()}"


class StaffLeave(models.Model):
    """
    Manages staff leave requests and approvals.
    
    This model handles all types of leave requests, tracking the
    approval workflow and leave balances.
    
    Attributes:
        staff (ForeignKey): Staff member requesting leave
        leave_type (str): Type of leave from LEAVE_TYPE_CHOICES
        start_date (date): Leave start date
        end_date (date): Leave end date
        days_requested (int): Number of days requested
        reason (str): Reason for leave
        status (str): Request status from STATUS_CHOICES
        approved_by (ForeignKey): Staff who approved the request
        approved_date (date): Date of approval
        remarks (str): Additional remarks
        created_at (datetime): When request was created
        updated_at (datetime): When request was last updated
    """
    
    LEAVE_TYPE_CHOICES = [
        ('annual', 'Annual Leave'),
        ('sick', 'Sick Leave'),
        ('maternity', 'Maternity Leave'),
        ('paternity', 'Paternity Leave'),
        ('bereavement', 'Bereavement'),
        ('unpaid', 'Unpaid Leave'),
        ('training', 'Training Leave'),
    ]
    
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('cancelled', 'Cancelled'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='leave_requests'
    )
    leave_type = models.CharField(
        max_length=20, 
        choices=LEAVE_TYPE_CHOICES
    )
    start_date = models.DateField()
    end_date = models.DateField()
    days_requested = models.PositiveIntegerField()
    reason = models.TextField()
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='pending'
    )
    approved_by = models.ForeignKey(
        Staff, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='approved_leaves'
    )
    approved_date = models.DateField(
        null=True, 
        blank=True
    )
    remarks = models.TextField(
        blank=True
    )
    
    created_at = models.DateTimeField(
        auto_now_add=True
    )
    updated_at = models.DateTimeField(
        auto_now=True
    )
    
    class Meta:
        ordering = ['-created_at']
        verbose_name = "Staff Leave"
        verbose_name_plural = "Staff Leaves"
    
    def __str__(self):
        """Return string representation of leave request."""
        return f"{self.staff} - {self.get_leave_type_display()} ({self.start_date} to {self.end_date})"
    
    def save(self, *args, **kwargs):
        """
        Save leave request with auto-calculated days.
        
        Calculates the number of days based on start and end dates.
        """
        if not self.days_requested:
            self.days_requested = (self.end_date - self.start_date).days + 1
        super().save(*args, **kwargs)


class StaffDocument(models.Model):
    """
    Stores additional documents for staff members.
    
    This model allows uploading and organizing various documents
    related to staff employment and qualifications.
    
    Attributes:
        staff (ForeignKey): Staff member this document belongs to
        document_type (str): Type of document from DOCUMENT_TYPE_CHOICES
        title (str): Document title
        file (FileField): The uploaded file
        uploaded_at (datetime): When document was uploaded
        notes (str): Additional notes about the document
    """
    
    DOCUMENT_TYPE_CHOICES = [
        ('contract', 'Employment Contract'),
        ('diploma', 'Diploma/Certificate'),
        ('id', 'ID Card'),
        ('cv', 'CV/Resume'),
        ('medical', 'Medical Certificate'),
        ('other', 'Other'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='documents'
    )
    document_type = models.CharField(
        max_length=20, 
        choices=DOCUMENT_TYPE_CHOICES
    )
    title = models.CharField(
        max_length=200
    )
    file = models.FileField(
        upload_to='staff/documents/'
    )
    uploaded_at = models.DateTimeField(
        auto_now_add=True
    )
    notes = models.TextField(
        blank=True
    )
    
    class Meta:
        ordering = ['-uploaded_at']
        verbose_name = "Staff Document"
        verbose_name_plural = "Staff Documents"
    
    def __str__(self):
        """Return string representation of the document."""
        return f"{self.staff} - {self.title}"