from django.db import models
from django.conf import settings
from django.utils import timezone


class Program(models.Model):
    JUNIOR_CERT = 'junior_certificate'
    NATIONAL_CERT = 'national_certificate'
    DIPLOMA = 'diploma'

    LEVEL_CHOICES = [
        (JUNIOR_CERT, 'Junior Certificate (3 Years)'),
        (NATIONAL_CERT, 'National Certificate (2 Years)'),
        (DIPLOMA, 'Diploma (2 Years)'),
    ]

    name = models.CharField(max_length=150)
    level = models.CharField(max_length=30, choices=LEVEL_CHOICES)
    duration = models.CharField(max_length=50)
    tuition_fee = models.DecimalField(max_digits=12, decimal_places=2)
    practical_fee = models.DecimalField(max_digits=12, decimal_places=2)
    assessment_fee = models.DecimalField(max_digits=12, decimal_places=2)
    exam_fee = models.DecimalField(
        max_digits=12, decimal_places=2, default=0,
        help_text='Exam fee charged per sitting (e.g. UGX 50,000). Set to 0 if not applicable. Note: exam fees may vary from time to time.',
    )
    entry_requirement = models.CharField(max_length=200, blank=True)
    description = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)
    content_access_percentage = models.PositiveIntegerField(
        default=50,
        help_text='Minimum % of total fees paid to unlock course content (0 = free for all).',
    )

    class Meta:
        ordering = ['level', 'name']

    def __str__(self):
        return f"{self.name} ({self.get_level_display()})"

    @property
    def total_fee_per_term(self):
        return self.tuition_fee + self.practical_fee + self.assessment_fee + self.exam_fee


class Application(models.Model):
    AWAITING_PAYMENT = 'awaiting_payment'
    PENDING = 'pending'
    UNDER_REVIEW = 'under_review'
    APPROVED = 'approved'
    REJECTED = 'rejected'

    STATUS_CHOICES = [
        (AWAITING_PAYMENT, 'Awaiting Fee Payment'),
        (PENDING, 'Pending'),
        (UNDER_REVIEW, 'Under Review'),
        (APPROVED, 'Approved'),
        (REJECTED, 'Rejected'),
    ]

    APPLICATION_FEE = 50000

    GENDER_CHOICES = [
        ('male', 'Male'),
        ('female', 'Female'),
        ('other', 'Other'),
    ]

    EDUCATION_CHOICES = [
        ('primary', 'PLE (Primary)'),
        ('o_level', 'UCE (O-Level)'),
        ('a_level', 'UACE (A-Level)'),
        ('certificate', 'Certificate'),
        ('diploma', 'Diploma'),
        ('degree', 'Degree'),
        ('other', 'Other'),
    ]

    EXAM_BODY_CHOICES = [
        ('UNEB', 'UNEB'),
        ('other', 'Other'),
    ]

    RELATIONSHIP_CHOICES = [
        ('father', 'Father'),
        ('mother', 'Mother'),
        ('parent', 'Parent'),
        ('guardian', 'Guardian'),
        ('sibling', 'Sibling'),
        ('spouse', 'Spouse'),
        ('relative', 'Other Relative'),
        ('friend', 'Friend'),
    ]

    # Linked user account (set on approval)
    applicant_user = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='application'
    )

    # ------------------------------------------------------------------ #
    # Section 1 — Personal Information
    # ------------------------------------------------------------------ #
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    other_names = models.CharField(max_length=100, blank=True)
    date_of_birth = models.DateField()
    gender = models.CharField(max_length=10, choices=GENDER_CHOICES)
    nationality = models.CharField(max_length=100, default='Ugandan')
    phone_number = models.CharField(max_length=20)
    email = models.EmailField()
    physical_address = models.TextField(help_text='Village, Parish, Sub-county')
    district = models.CharField(max_length=100, blank=True)
    # kept for admin identity verification — not shown on public form
    national_id = models.CharField(max_length=50, blank=True, verbose_name='National ID / Passport No.')

    # ------------------------------------------------------------------ #
    # Section 2A — Academic Qualifications
    # ------------------------------------------------------------------ #
    highest_education_level = models.CharField(max_length=20, choices=EDUCATION_CHOICES)
    education_other = models.CharField(max_length=100, blank=True, verbose_name='Other Qualification (specify)')
    year_of_completion = models.PositiveIntegerField()
    last_school_attended = models.CharField(max_length=200, verbose_name='Name of Last Institution Attended')
    institution_location = models.CharField(
        max_length=200, blank=True,
        verbose_name='Location of Institution (District/Country)'
    )

    # ------------------------------------------------------------------ #
    # Section 2B — National Examination Details
    # ------------------------------------------------------------------ #
    exam_index_number = models.CharField(max_length=50, blank=True, verbose_name='Index Number (UCE/UACE/Other)')
    exam_body = models.CharField(max_length=20, choices=EXAM_BODY_CHOICES, blank=True, verbose_name='Examination Body')
    exam_body_other = models.CharField(max_length=100, blank=True, verbose_name='Other Examination Body')
    exam_year = models.PositiveIntegerField(null=True, blank=True, verbose_name='Year of Examination')
    exam_grade = models.CharField(max_length=50, blank=True, verbose_name='Grade / Result Achieved')

    # ------------------------------------------------------------------ #
    # Section 2C — Skills-Based / Non-Formal Education
    # ------------------------------------------------------------------ #
    non_formal_level = models.CharField(max_length=200, blank=True, verbose_name='Highest Non-Formal Level Attained')
    apprenticeship_details = models.TextField(blank=True, verbose_name='Apprenticeship / Training Undertaken')
    practical_experience = models.TextField(blank=True, verbose_name='Relevant Work or Practical Experience')

    # ------------------------------------------------------------------ #
    # Section 3 — Former School / Institute Details
    # ------------------------------------------------------------------ #
    former_institution_name = models.CharField(max_length=200, blank=True, verbose_name='Name of Former Institution')
    former_institution_level = models.CharField(max_length=100, blank=True, verbose_name='Level Completed')
    former_institution_year = models.PositiveIntegerField(null=True, blank=True, verbose_name='Year Completed')
    former_institution_district = models.CharField(max_length=100, blank=True, verbose_name='District / Location')

    # ------------------------------------------------------------------ #
    # Section 4 — Work Experience
    # ------------------------------------------------------------------ #
    current_occupation = models.CharField(max_length=200, blank=True)
    employer_name = models.CharField(max_length=200, blank=True, verbose_name='Employer / Organization')
    years_of_experience = models.CharField(max_length=50, blank=True)
    work_duties = models.TextField(blank=True, verbose_name='Brief Description of Duties')
    additional_qualifications = models.TextField(
        blank=True,
        verbose_name='Additional Qualifications / Experience',
        help_text='Any extra qualifications, certifications, jobs, or experience not covered above.',
    )

    # ------------------------------------------------------------------ #
    # Section 5 — Primary Next of Kin
    # ------------------------------------------------------------------ #
    emergency_contact_name = models.CharField(max_length=200, verbose_name='Primary Next of Kin Name')
    emergency_contact_relationship = models.CharField(
        max_length=20, choices=RELATIONSHIP_CHOICES,
        verbose_name='Relationship'
    )
    emergency_contact_phone = models.CharField(max_length=20, verbose_name='Phone Number')
    emergency_contact_email = models.EmailField(blank=True, verbose_name='Email Address')
    emergency_contact_occupation = models.CharField(max_length=200, blank=True, verbose_name='Occupation')
    emergency_contact_address = models.TextField(blank=True, verbose_name='Address')

    # Section 5 — Secondary Next of Kin
    secondary_contact_name = models.CharField(max_length=200, blank=True, verbose_name='Secondary Next of Kin Name')
    secondary_contact_relationship = models.CharField(
        max_length=20, choices=RELATIONSHIP_CHOICES, blank=True,
        verbose_name='Relationship'
    )
    secondary_contact_phone = models.CharField(max_length=20, blank=True, verbose_name='Phone Number')
    secondary_contact_email = models.EmailField(blank=True, verbose_name='Email Address')
    secondary_contact_occupation = models.CharField(max_length=200, blank=True, verbose_name='Occupation')
    secondary_contact_address = models.TextField(blank=True, verbose_name='Address')

    # ------------------------------------------------------------------ #
    # Section 6 — Program Application
    # ------------------------------------------------------------------ #
    program_applied = models.ForeignKey(Program, on_delete=models.PROTECT, related_name='applications')
    preferred_start_date = models.CharField(max_length=100, blank=True)

    # ------------------------------------------------------------------ #
    # Section 7 — Skills Profile
    # ------------------------------------------------------------------ #
    skills_profile = models.JSONField(default=list, blank=True)
    skills_other = models.CharField(max_length=200, blank=True, verbose_name='Other Skill (specify)')

    # ------------------------------------------------------------------ #
    # Application Fee (UGX 50,000 non-refundable)
    # ------------------------------------------------------------------ #
    application_fee_paid = models.BooleanField(default=False)
    application_fee_paid_at = models.DateTimeField(null=True, blank=True)
    application_fee_txref = models.CharField(max_length=100, blank=True)
    application_fee_transaction_id = models.CharField(max_length=100, blank=True)

    # ------------------------------------------------------------------ #
    # Admin / Status fields
    # ------------------------------------------------------------------ #
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=AWAITING_PAYMENT)
    admin_notes = models.TextField(blank=True, help_text='Internal notes (not sent to applicant)')
    rejection_reason = models.TextField(blank=True, help_text='Reason sent to applicant on rejection')
    reviewed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='reviewed_applications'
    )
    submitted_at = models.DateTimeField(auto_now_add=True)
    reviewed_at = models.DateTimeField(null=True, blank=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-submitted_at']

    def __str__(self):
        return f"{self.full_name} → {self.program_applied} [{self.get_status_display()}]"

    @property
    def full_name(self):
        parts = [self.first_name]
        if self.other_names:
            parts.append(self.other_names)
        parts.append(self.last_name)
        return ' '.join(parts)

    @property
    def reference_number(self):
        return f"MLS-APP-{self.pk:05d}"

    def get_status_badge_class(self):
        return {
            self.AWAITING_PAYMENT: 'bg-danger text-white',
            self.PENDING: 'bg-warning text-dark',
            self.UNDER_REVIEW: 'bg-info text-dark',
            self.APPROVED: 'bg-success',
            self.REJECTED: 'bg-danger',
        }.get(self.status, 'bg-secondary')


class ApplicationDocument(models.Model):
    O_LEVEL = 'o_level_results'
    A_LEVEL = 'a_level_results'
    CERTIFICATE = 'certificate'
    NATIONAL_ID = 'national_id'
    PASSPORT_PHOTO = 'passport_photo'

    DOCUMENT_TYPE_CHOICES = [
        (O_LEVEL, 'O-Level Results (UCE)'),
        (A_LEVEL, 'A-Level Results (UACE)'),
        (CERTIFICATE, 'Certificate'),
        (NATIONAL_ID, 'National ID / Passport Copy'),
        (PASSPORT_PHOTO, 'Passport-size Photo'),
    ]

    application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='documents')
    document_type = models.CharField(max_length=50, choices=DOCUMENT_TYPE_CHOICES)
    file = models.FileField(upload_to='application_documents/%Y/%m/')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    is_verified = models.BooleanField(default=False)

    class Meta:
        unique_together = ['application', 'document_type']

    def __str__(self):
        return f"{self.application.full_name} — {self.get_document_type_display()}"

    @property
    def filename(self):
        return self.file.name.split('/')[-1]


class Enrollment(models.Model):
    CONTENT_DEFAULT  = 'default'
    CONTENT_ENABLED  = 'enabled'
    CONTENT_DISABLED = 'disabled'
    CONTENT_ACCESS_OVERRIDE_CHOICES = [
        ('default',  'Default (use payment threshold)'),
        ('enabled',  'Force Enabled (bypass payment gate)'),
        ('disabled', 'Force Disabled (lock even if paid)'),
    ]

    student = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='enrollment'
    )
    application = models.OneToOneField(Application, on_delete=models.PROTECT, related_name='enrollment', null=True, blank=True)
    program = models.ForeignKey(Program, on_delete=models.PROTECT, related_name='enrollments')
    student_number = models.CharField(max_length=20, unique=True, blank=True)
    enrolled_at = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    edits_unlocked = models.BooleanField(
        default=False,
        help_text='When enabled, the student may edit their contact details and re-upload documents.',
    )
    content_access_override = models.CharField(
        max_length=10,
        choices=CONTENT_ACCESS_OVERRIDE_CHOICES,
        default='default',
    )

    class Meta:
        ordering = ['-enrolled_at']

    def __str__(self):
        return f"{self.student_number} — {self.student.get_full_name()} ({self.program})"

    def save(self, *args, **kwargs):
        if not self.student_number:
            year = timezone.now().year
            count = Enrollment.objects.filter(enrolled_at__year=year).count() + 1
            self.student_number = f"MLS-{year}-{count:05d}"
        super().save(*args, **kwargs)
