from django.conf import settings
from django.core.validators import MaxValueValidator
from django.db import models


class PipelineStage(models.Model):
    """Master list of recruitment pipeline stages. Data-driven so admins can
    add / reorder / deactivate stages without code changes."""

    class Outcome(models.TextChoices):
        IN_PROGRESS = "IN_PROGRESS", "In Progress"
        WON = "WON", "Won"
        LOST = "LOST", "Lost"

    name = models.CharField(max_length=100, unique=True)
    code = models.SlugField(max_length=50, unique=True)
    sort_order = models.PositiveIntegerField(default=0)
    outcome = models.CharField(max_length=20, choices=Outcome.choices, default=Outcome.IN_PROGRESS)
    is_active = models.BooleanField(default=True)

    class Meta:
        db_table = "pipeline_stages"
        ordering = ["sort_order", "id"]

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


class JobApplication(models.Model):
    """A candidate placed into a JD's pipeline at a given stage.
    No row = candidate is in the general pool (not assigned to any JD)."""

    candidate = models.ForeignKey(
        "candidates.Candidate", on_delete=models.CASCADE, related_name="applications"
    )
    job = models.ForeignKey(
        "jobs.JobDescription", on_delete=models.CASCADE, related_name="applications"
    )
    stage = models.ForeignKey(
        PipelineStage, on_delete=models.SET_NULL, null=True, blank=True, related_name="applications"
    )
    # Interview tracking
    interviewer = models.CharField(max_length=150, blank=True, default="")
    interview_date = models.DateField(null=True, blank=True)
    interview_result = models.CharField(max_length=30, blank=True, default="")
    remark = models.TextField(blank=True, default="")

    class ActivityType(models.TextChoices):
        EMAIL = "Email", "Email"
        CALL = "Call", "Call"
        CALL_TALKED = "Call (talked)", "Call (talked)"
        CALL_LVM = "Call (LVM)", "Call (LVM)"
        MEETING = "Meeting", "Meeting"
        OTHER = "Other", "Other"

    activity = models.CharField(max_length=50, choices=ActivityType.choices, blank=True, default="")

    # OUT-003: Round-1 outreach outcome
    class Round1Outcome(models.TextChoices):
        SCREENED_IN = "SCREENED_IN", "Screened-In"
        SCREENED_OUT = "SCREENED_OUT", "Screened-Out"
        CALL_LATER = "CALL_LATER", "Call Me Later"
        NOT_INTERESTED = "NOT_INTERESTED", "Not Interested"
        NO_RESPONSE = "NO_RESPONSE", "No Response"
        DEALBREAKER = "DEALBREAKER", "Dealbreaker"

    round1_outcome = models.CharField(max_length=20, choices=Round1Outcome.choices, blank=True, default="")
    # OUT-002: candidate's answers to the JD screening questions [{question, expected, answer}]
    screening_answers = models.JSONField(default=list, blank=True)
    # AI/manual screening score of the candidate against this JD (0-100).
    score = models.PositiveSmallIntegerField(
        null=True, blank=True, validators=[MaxValueValidator(100)]
    )

    # Screening-email dispatch status, tracked per candidate per JD. Set when a
    # recruiter emails selected candidates after AI screening/ranking. Additive:
    # does not affect ranking, scoring, or any existing pipeline behaviour.
    class EmailStatus(models.TextChoices):
        NOT_SENT = "NOT_SENT", "Not Sent"
        SENT = "SENT", "Sent"
        FAILED = "FAILED", "Failed"

    email_status = models.CharField(
        max_length=10, choices=EmailStatus.choices, default=EmailStatus.NOT_SENT
    )
    email_sent_at = models.DateTimeField(null=True, blank=True)

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True,
        related_name="created_applications",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "job_applications"
        ordering = ["-created_at"]
        unique_together = ("candidate", "job")   # a candidate can't be added to the same JD twice

    def __str__(self):
        return f"{self.candidate_id} -> {self.job_id} [{self.stage_id}]"


class RankRun(models.Model):
    """One AI ranking run for a JD — stores inputs/weights snapshot for audit (RANK-008)."""
    job = models.ForeignKey("jobs.JobDescription", on_delete=models.CASCADE, related_name="rank_runs")
    weights = models.JSONField(default=dict, blank=True, help_text="Parameter weights used for this run.")
    provider_name = models.CharField(max_length=120, blank=True, default="")
    candidate_count = models.PositiveIntegerField(default=0)
    top_n = models.PositiveIntegerField(default=5)
    run_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="rank_runs")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "rank_runs"
        ordering = ["-created_at"]
        # Dedicated RBAC permission for the "Rank Candidates" action. Assignable
        # to any role via Groups & Permissions; gates the ranking button (UI) and
        # the ranking API (backend). String: "pipeline.rank_candidates".
        permissions = [("rank_candidates", "Can rank candidates")]


class RankScore(models.Model):
    """Per-candidate result of a RankRun (RANK-004: overall + per-parameter + rationale)."""
    run = models.ForeignKey(RankRun, on_delete=models.CASCADE, related_name="scores")
    application = models.ForeignKey(JobApplication, null=True, blank=True, on_delete=models.SET_NULL, related_name="rank_scores")
    candidate = models.ForeignKey("candidates.Candidate", on_delete=models.CASCADE, related_name="rank_scores")
    overall_score = models.PositiveSmallIntegerField(default=0)   # 0-100
    parameter_scores = models.JSONField(default=dict, blank=True)  # {"skills": 8, "experience": 6, ...}
    rationale = models.TextField(blank=True, default="")
    is_top = models.BooleanField(default=False)
    # RANK-006: manual override with mandatory reason
    manual_override = models.PositiveSmallIntegerField(null=True, blank=True)
    override_reason = models.TextField(blank=True, default="")
    overridden_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="rank_overrides")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "rank_scores"
        ordering = ["-overall_score"]

    @property
    def effective_score(self):
        return self.manual_override if self.manual_override is not None else self.overall_score


class RankParameter(models.Model):
    """Configurable scoring parameter for the AI ranking engine (RANK-003).
    Admins add/edit these with NO code change; the ranking prompt is built
    dynamically from the active parameters."""
    key = models.SlugField(max_length=50, unique=True, help_text="Machine key, e.g. 'communication'")
    label = models.CharField(max_length=100, help_text="Display name, e.g. 'Communication Skills'")
    description = models.TextField(blank=True, default="",
        help_text="Guidance sent to the AI on how to judge this parameter.")
    weight = models.PositiveSmallIntegerField(default=10, help_text="Default weight (share of 100).")
    is_active = models.BooleanField(default=True)
    sort_order = models.PositiveSmallIntegerField(default=0)

    class Meta:
        db_table = "rank_parameters"
        ordering = ["sort_order", "id"]

    def __str__(self):
        return f"{self.label} ({self.key})"


class InterviewFeedback(models.Model):
    """R2-003/004: structured technical-round feedback, attached to a pipeline entry."""
    class Recommendation(models.TextChoices):
        STRONG_YES = "STRONG_YES", "Strong Yes"
        YES = "YES", "Yes"
        MAYBE = "MAYBE", "Maybe"
        NO = "NO", "No"
        STRONG_NO = "STRONG_NO", "Strong No"

    class Round(models.TextChoices):
        TECHNICAL = "TECHNICAL", "Technical (Round 2)"
        FINAL = "FINAL", "Customer / Final (Round 3)"

    application = models.ForeignKey(JobApplication, on_delete=models.CASCADE, related_name="feedbacks")
    round = models.CharField(max_length=20, choices=Round.choices, default=Round.TECHNICAL)
    interviewer = models.CharField(max_length=150, blank=True, default="")
    # per-competency scores, e.g. {"problem_solving": 8, "coding": 7, "communication": 9}
    scores = models.JSONField(default=dict, blank=True)
    overall_score = models.PositiveSmallIntegerField(null=True, blank=True, validators=[MaxValueValidator(100)])
    strengths = models.TextField(blank=True, default="")
    weaknesses = models.TextField(blank=True, default="")
    recommendation = models.CharField(max_length=20, choices=Recommendation.choices, blank=True, default="")
    notes = models.TextField(blank=True, default="")
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="interview_feedbacks")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "interview_feedback"
        ordering = ["-created_at"]


class InterviewSchedule(models.Model):
    """R2-001/002/006: a scheduled interview round with reschedule/cancel + reason."""
    class Status(models.TextChoices):
        SCHEDULED = "SCHEDULED", "Scheduled"
        RESCHEDULED = "RESCHEDULED", "Rescheduled"
        CANCELLED = "CANCELLED", "Cancelled"
        COMPLETED = "COMPLETED", "Completed"

    application = models.ForeignKey(JobApplication, on_delete=models.CASCADE, related_name="schedules")
    round = models.CharField(max_length=20, default="TECHNICAL")
    interviewer = models.CharField(max_length=150, blank=True, default="")
    interviewer_email = models.EmailField(blank=True, default="")
    scheduled_at = models.DateTimeField(null=True, blank=True)
    duration_minutes = models.PositiveIntegerField(default=45)
    location = models.CharField(max_length=255, blank=True, default="", help_text="Meeting link or venue")
    status = models.CharField(max_length=15, choices=Status.choices, default=Status.SCHEDULED)
    reason = models.TextField(blank=True, default="", help_text="Reason for reschedule/cancellation")
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="interview_schedules")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "interview_schedules"
        ordering = ["-scheduled_at", "-created_at"]


class Shortlist(models.Model):
    """R3-001/002: a customer-shareable shortlist for a JD (secure token link)."""
    import uuid as _uuid
    job = models.ForeignKey("jobs.JobDescription", on_delete=models.CASCADE, related_name="shortlists")
    token = models.CharField(max_length=40, unique=True, db_index=True)
    title = models.CharField(max_length=200, blank=True, default="")
    note = models.TextField(blank=True, default="")
    is_active = models.BooleanField(default=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="shortlists")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "shortlists"
        ordering = ["-created_at"]

    @staticmethod
    def new_token():
        import secrets
        return secrets.token_urlsafe(24)[:40]


class ShortlistItem(models.Model):
    """A candidate on a shortlist + the customer's pick/comment (R3-002/005)."""
    class Result(models.TextChoices):
        PENDING = "PENDING", "Pending"
        SELECTED = "SELECTED", "Selected"
        REJECTED = "REJECTED", "Rejected"
        HOLD = "HOLD", "Hold"
        BACKUP = "BACKUP", "Backup"

    shortlist = models.ForeignKey(Shortlist, on_delete=models.CASCADE, related_name="items")
    application = models.ForeignKey(JobApplication, on_delete=models.CASCADE, related_name="shortlist_items")
    picked = models.BooleanField(default=False)               # customer picked for final interview
    customer_comment = models.TextField(blank=True, default="")
    final_result = models.CharField(max_length=10, choices=Result.choices, default=Result.PENDING)

    class Meta:
        db_table = "shortlist_items"
        unique_together = ("shortlist", "application")


class PipelineLog(models.Model):
    """Activity/Change log for candidate pipeline entries."""
    application = models.ForeignKey(
        JobApplication, on_delete=models.CASCADE, related_name="logs"
    )
    candidate = models.ForeignKey(
        "candidates.Candidate", on_delete=models.CASCADE, related_name="pipeline_logs"
    )
    job = models.ForeignKey(
        "jobs.JobDescription", on_delete=models.CASCADE, related_name="pipeline_logs"
    )
    performed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="pipeline_logs"
    )
    status_name = models.CharField(max_length=100, blank=True, default="")
    activity = models.CharField(max_length=50, blank=True, default="")
    remark = models.TextField(blank=True, default="")
    changes_summary = models.TextField(blank=True, default="")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "pipeline_logs"
        ordering = ["-created_at"]

    def __str__(self):
        return f"Log for App {self.application_id} at {self.created_at}"
