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

from apps.core.authentication.models import UserProfile
from apps.core.storage import FileValidator
from apps.core.storage.paths import upload_to_cv

_rep_cv_doc_validator = FileValidator(module="rep", allowed_categories=["document"])


class JobListing(models.Model):
    class JobType(models.TextChoices):
        FULL_TIME = "full_time", "Full-time"
        PART_TIME = "part_time", "Part-time"
        INTERNSHIP = "internship", "Internship"
        CONTRACT = "contract", "Contract"

    class ListingStatus(models.TextChoices):
        DRAFT = "draft", "Draft"
        PENDING = "pending", "Pending approval"
        PUBLISHED = "published", "Published"
        REJECTED = "rejected", "Rejected"
        EXPIRED = "expired", "Expired"

    class Audience(models.TextChoices):
        ALL = "all", "All learners + alumni"
        LEARNERS = "learners", "REP learners only"
        ALUMNI = "alumni", "Alumni only"

    SECTOR_CHOICES = [
        ("Agriculture / Food Systems", "Agriculture / Food Systems"),
        ("Biotechnology", "Biotechnology"),
        ("Climate & Environment", "Climate & Environment"),
        ("Data Science & Analytics", "Data Science & Analytics"),
        ("Education & Training", "Education & Training"),
        ("Finance & Grants Management", "Finance & Grants Management"),
        ("Health & Nutrition", "Health & Nutrition"),
        ("ICT & Digital Innovation", "ICT & Digital Innovation"),
        ("Natural Resources", "Natural Resources"),
        ("Policy & Advocacy", "Policy & Advocacy"),
        ("Research & Development", "Research & Development"),
        ("Rural Development", "Rural Development"),
        ("Seed Systems & Agronomy", "Seed Systems & Agronomy"),
        ("Social Sciences", "Social Sciences"),
        ("Water & Sanitation", "Water & Sanitation"),
    ]

    title = models.CharField(max_length=255)
    company = models.CharField(max_length=255)
    location = models.CharField(max_length=255, blank=True)
    # FRREP-TS002 — SRS-mandated "country" filter facet. Free-text ``location``
    # (city/remote/etc.) stays as-is; ``country`` is the canonical full-name
    # value (see apps.core.countries.to_country_name) so it can be searched
    # and faceted the same way as everywhere else in the codebase.
    country = models.CharField(
        max_length=100,
        blank=True,
        help_text="Full country name where this position is based (optional).",
    )
    job_type = models.CharField(max_length=16, choices=JobType.choices, default=JobType.FULL_TIME)
    description = models.TextField()
    requirements = models.TextField(blank=True)
    # FRREP-TS002 — SRS-mandated "qualification requirements" filter facet.
    # Reuses UserProfile.DegreeLevel (already the canonical education-level
    # ladder used for grant eligibility) rather than inventing a second
    # taxonomy for the same concept.
    min_qualification = models.CharField(
        max_length=32,
        choices=UserProfile.DegreeLevel.choices,
        blank=True,
        help_text="Minimum qualification required for this role (optional).",
    )
    salary_range = models.CharField(max_length=128, blank=True)
    sector = models.CharField(max_length=128, blank=True)
    posted_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="rep_job_listings",
    )
    closes_at = models.DateField(null=True, blank=True)
    is_active = models.BooleanField(default=True, db_index=True)
    listing_status = models.CharField(
        max_length=16,
        choices=ListingStatus.choices,
        default=ListingStatus.PUBLISHED,
        db_index=True,
    )
    employer_notes = models.TextField(blank=True, help_text="Admin feedback when returning a listing.")
    audience = models.CharField(
        max_length=16,
        choices=Audience.choices,
        default=Audience.ALL,
        db_index=True,
        help_text="Which audience sees this listing on its dedicated job board.",
    )
    submitted_by_partner = models.ForeignKey(
        "smehub_linkage.PartnerDirectoryEntry",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="alumni_job_submissions",
        help_text="Set when the listing was submitted via the alumni partner submission flow.",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]
        permissions = [
            ("post_job_listing", "Can post job listings as an employer/partner"),
        ]

    def __str__(self):
        return f"{self.title} — {self.company}"

    @property
    def closes_soon(self) -> bool:
        """True if the listing closes within the next 7 days."""
        from datetime import date, timedelta
        if self.closes_at:
            return self.closes_at <= date.today() + timedelta(days=7)
        return False


class CVProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="rep_cv",
    )
    headline = models.CharField(max_length=255, blank=True)
    summary = models.TextField(blank=True)
    cv_document = models.FileField(
        upload_to=upload_to_cv,
        blank=True,
        null=True,
        validators=[_rep_cv_doc_validator],
        help_text="Optional PDF or Word CV; shown to recruiters in addition to structured sections.",
    )
    is_public = models.BooleanField(default=False)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"CV — {self.user.email}"


class CVSection(models.Model):
    class SectionType(models.TextChoices):
        EDUCATION = "education", "Education"
        EXPERIENCE = "experience", "Work experience"
        SKILLS = "skills", "Skills"
        CERTIFICATIONS = "certifications", "Certifications"
        PUBLICATIONS = "publications", "Publications"
        LANGUAGES = "languages", "Languages"
        REFERENCES = "references", "References"

    cv = models.ForeignKey(CVProfile, on_delete=models.CASCADE, related_name="sections")
    section_type = models.CharField(max_length=32, choices=SectionType.choices)
    data = models.JSONField(default=list)
    sort_order = models.PositiveSmallIntegerField(default=0)

    class Meta:
        ordering = ["sort_order", "pk"]
        constraints = [
            models.UniqueConstraint(
                fields=["cv", "section_type"],
                name="uniq_rep_cv_section_per_type",
            ),
        ]

    def __str__(self):
        return f"{self.cv.user.email} — {self.get_section_type_display()}"


class JobApplication(models.Model):
    class Status(models.TextChoices):
        APPLIED = "applied", "Applied"
        SHORTLISTED = "shortlisted", "Shortlisted"
        REJECTED = "rejected", "Rejected"
        HIRED = "hired", "Hired"

    listing = models.ForeignKey(JobListing, on_delete=models.CASCADE, related_name="applications")
    applicant = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="rep_job_applications",
    )
    cv_snapshot = models.JSONField(default=dict, blank=True)
    cover_letter = models.TextField(blank=True)
    cover_letter_file = models.FileField(
        upload_to=upload_to_cv,
        blank=True,
        null=True,
        validators=[_rep_cv_doc_validator],
    )
    status = models.CharField(max_length=16, choices=Status.choices, default=Status.APPLIED)
    applied_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-applied_at"]
        constraints = [
            models.UniqueConstraint(fields=["listing", "applicant"], name="uniq_rep_job_application"),
        ]

    def __str__(self):
        return f"{self.applicant.email} → {self.listing.title}"


class CareerResource(models.Model):
    class ResourceType(models.TextChoices):
        ARTICLE = "article", "Article"
        VIDEO = "video", "Video"
        LINK = "link", "External link"

    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=160, unique=True)
    resource_type = models.CharField(
        max_length=16, choices=ResourceType.choices, default=ResourceType.ARTICLE
    )
    body = models.TextField(blank=True, help_text="HTML or plain text for articles.")
    url = models.URLField(blank=True, help_text="Video or external link URL.")
    tags = models.CharField(max_length=512, blank=True, help_text="Comma-separated tags.")
    career_stage = models.CharField(max_length=64, blank=True, db_index=True)
    is_published = models.BooleanField(default=True, db_index=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="rep_career_resources_created",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return self.title


class CareerResourceAccessLog(models.Model):
    resource = models.ForeignKey(CareerResource, on_delete=models.CASCADE, related_name="access_logs")
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="rep_career_resource_access",
    )
    accessed_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-accessed_at"]


class AlumniHandoff(models.Model):
    """Per-event record of the REP → Alumni module transfer (FRREP-TS007).

    The SRS mandates "transfer confirmed and logged". This model is the
    system-of-record: every course/programme completion that triggers an
    alumni webhook produces exactly one row, mutated through a status FSM
    (PENDING → SENT → CONFIRMED, or FAILED with a retry budget).

    The Alumni system can return a JSON body containing ``reference_id`` on
    successful POST — that id is captured here so future operations can
    cross-reference the alumni-side record without re-deriving it.
    """

    class Status(models.TextChoices):
        PENDING = "pending", "Pending"
        SENT = "sent", "Sent"
        CONFIRMED = "confirmed", "Confirmed"
        FAILED = "failed", "Failed"

    learner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="alumni_handoffs",
    )
    # Formerly a FK to ``rep_courses.Enrolment``. The REP LMS was retired in
    # favour of Moodle, so the upstream completion id is now stored as a plain
    # string (legacy REP enrolment pk, or a Moodle completion ref going forward).
    enrolment_ref = models.CharField(
        max_length=64,
        blank=True,
        help_text="Upstream enrolment/completion id (legacy REP enrolment pk or Moodle completion ref).",
    )
    payload = models.JSONField()
    status = models.CharField(
        max_length=12,
        choices=Status.choices,
        default=Status.PENDING,
        db_index=True,
    )
    attempts = models.PositiveSmallIntegerField(default=0)
    last_error = models.TextField(blank=True)
    alumni_module_reference = models.CharField(
        max_length=120,
        blank=True,
        help_text="Reference id returned by the Alumni system on acknowledgement.",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    sent_at = models.DateTimeField(null=True, blank=True)
    confirmed_at = models.DateTimeField(null=True, blank=True)

    MAX_ATTEMPTS = 5

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["status", "created_at"]),
            models.Index(fields=["learner", "status"]),
        ]

    def __str__(self) -> str:
        return f"AlumniHandoff #{self.pk} · {self.learner_id} · {self.status}"


# ── Saved jobs / bookmarks (FRREP-TS008) ─────────────────────────────────
#
# SRS: "allow learners to save job listings and track their application
# status." Application-status tracking already exists (JobApplication /
# MyApplicationsView); this adds the missing bookmarking half. Mirrors the
# repository module's DocumentBookmark pattern (apps.repository.documents.
# models.DocumentBookmark) for consistency across the codebase.
class SavedJob(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="rep_saved_jobs",
    )
    listing = models.ForeignKey(
        JobListing,
        on_delete=models.CASCADE,
        related_name="saved_by",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]
        constraints = [
            models.UniqueConstraint(
                fields=["user", "listing"], name="uniq_rep_saved_job_user_listing"
            ),
        ]

    def __str__(self) -> str:
        return f"{self.user.email} ☆ {self.listing.title}"
