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


class AICall(models.Model):
    """One AI screening call for a candidate against a JD.

    A retry reuses the same row (attempts increments) so the listing always
    shows the latest state per candidate-job pair. The full lifecycle:

        QUEUED -> DIALING -> IN_PROGRESS -> COMPLETED
                                         -> NO_ANSWER / FAILED   (retryable)

    On completion the linked JobApplication is moved to the AI Screened /
    AI Qualified pipeline stage and its `score` is set, so the Reports
    module picks the result up automatically."""

    class Status(models.TextChoices):
        QUEUED = "QUEUED", "Queued"
        DIALING = "DIALING", "Dialing"
        IN_PROGRESS = "IN_PROGRESS", "In Progress"
        COMPLETED = "COMPLETED", "Completed"
        NO_ANSWER = "NO_ANSWER", "No Answer"
        # Distinct outcomes the provider reports. Previously `busy` was folded
        # into NO_ANSWER and a recruiter cancellation into FAILED, which hid why
        # a call did not connect.
        BUSY = "BUSY", "Busy"
        CANCELLED = "CANCELLED", "Cancelled"
        FAILED = "FAILED", "Failed"

    #: Outcomes that mean the call did NOT connect and complete. A summary,
    #: transcript, score or recommendation must never be presented for these.
    UNSUCCESSFUL_STATUSES = ("NO_ANSWER", "BUSY", "CANCELLED", "FAILED")

    class Recommendation(models.TextChoices):
        QUALIFIED = "QUALIFIED", "Qualified"
        REVIEW = "REVIEW", "Needs Review"
        NOT_QUALIFIED = "NOT_QUALIFIED", "Not Qualified"

    candidate = models.ForeignKey(
        "candidates.Candidate", on_delete=models.CASCADE, related_name="ai_calls"
    )
    job = models.ForeignKey(
        "jobs.JobDescription", on_delete=models.CASCADE, related_name="ai_calls"
    )
    application = models.ForeignKey(
        "pipeline.JobApplication", on_delete=models.SET_NULL, null=True, blank=True,
        related_name="ai_calls",
    )
    provider_call_id = models.CharField(max_length=100, blank=True, default="", db_index=True)
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.QUEUED, db_index=True)
    attempts = models.PositiveSmallIntegerField(default=0)
    started_at = models.DateTimeField(null=True, blank=True)
    ended_at = models.DateTimeField(null=True, blank=True)
    duration = models.PositiveIntegerField(null=True, blank=True, help_text="Call length in seconds.")
    transcript = models.TextField(blank=True, default="")
    summary = models.TextField(blank=True, default="")
    score = models.PositiveSmallIntegerField(null=True, blank=True)
    recommendation = models.CharField(
        max_length=20, choices=Recommendation.choices, blank=True, default=""
    )
    error_message = models.TextField(blank=True, default="")
    agent_variables = models.JSONField(default=dict, blank=True, help_text="Variables sent to the calling agent.")
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True,
        related_name="ai_calls_started",
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "ai_calls"
        ordering = ["-updated_at"]
        unique_together = ("candidate", "job")

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


class CallTranscriptUtterance(models.Model):
    """One turn of the conversation, as streamed by the calling platform.

    `AICall.transcript` (the flat text blob) remains for backward
    compatibility and is assembled from these rows on completion."""

    class Speaker(models.TextChoices):
        AGENT = "AGENT", "AI Agent"
        CANDIDATE = "CANDIDATE", "Candidate"

    call = models.ForeignKey(AICall, on_delete=models.CASCADE, related_name="utterances")
    sequence = models.PositiveIntegerField()
    speaker = models.CharField(max_length=10, choices=Speaker.choices)
    message = models.TextField()
    started_ms = models.PositiveIntegerField(null=True, blank=True, help_text="Offset into the call, ms.")
    ended_ms = models.PositiveIntegerField(null=True, blank=True)
    language = models.CharField(max_length=5, default="en")
    interrupted = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "ai_call_utterances"
        ordering = ["sequence", "id"]
        unique_together = ("call", "sequence")

    def __str__(self):
        return f"[{self.call_id}#{self.sequence}] {self.speaker}: {self.message[:40]}"


class CallEvaluation(models.Model):
    """Structured screening evaluation produced by the scoring engine."""

    class Classification(models.TextChoices):
        STRONG_MATCH = "Strong Match", "Strong Match"
        POTENTIAL_MATCH = "Potential Match", "Potential Match"
        NOT_SUITABLE = "Not Suitable", "Not Suitable"

    class Recommendation(models.TextChoices):
        PROCEED = "Proceed", "Proceed"
        HOLD = "Hold", "Hold"
        REJECT = "Reject", "Reject"

    call = models.OneToOneField(AICall, on_delete=models.CASCADE, related_name="evaluation")
    technical_score = models.PositiveSmallIntegerField(null=True, blank=True)
    communication_score = models.PositiveSmallIntegerField(null=True, blank=True)
    experience_score = models.PositiveSmallIntegerField(null=True, blank=True)
    confidence_score = models.PositiveSmallIntegerField(null=True, blank=True)
    overall_score = models.PositiveSmallIntegerField(null=True, blank=True)
    classification = models.CharField(max_length=20, choices=Classification.choices, blank=True, default="")
    recommendation = models.CharField(max_length=10, choices=Recommendation.choices, blank=True, default="")
    strengths = models.JSONField(default=list, blank=True)
    weaknesses = models.JSONField(default=list, blank=True)
    summary = models.TextField(blank=True, default="")
    rubric = models.JSONField(default=dict, blank=True, help_text="Per-question scores + evidence quotes.")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "ai_call_evaluations"

    def __str__(self):
        return f"Evaluation for call {self.call_id} ({self.overall_score})"


class VoiceAgent(models.Model):
    """Permission anchor only — no DB table is created (managed = False).

    Hunar is the source of truth for voice agents; the Voice Agents module
    proxies its API live and stores nothing locally. This model exists purely so
    the app owns the permissions that gate that module: the sidebar entries
    (Menu.permission_code) and every /api/v1/ai-calls/agents/ endpoint. ADMIN
    users bypass them; other roles receive them via their group.

    Same pattern as apps.reports.models.Report."""

    class Meta:
        managed = False
        default_permissions = ()
        permissions = [
            ("view_voiceagent", "Can view voice agents"),
            ("add_voiceagent", "Can create voice agents"),
            ("change_voiceagent", "Can edit voice agents"),
        ]

    def __str__(self):
        return "Voice Agent (permission anchor)"
