from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _

from .validators import (
    validate_phone_number,
    validate_resume_file,
    validate_document_file,
    validate_non_negative,
    validate_passing_year,
)
from .resume_storage import resume_storage, attachment_path


class Language(models.Model):
    """Model to store languages known by candidates."""
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        db_table = "candidate_languages"
        ordering = ["name"]

    def __str__(self) -> str:
        return self.name


class Skill(models.Model):
    """Model to store skill directory."""
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        db_table = "candidate_skills"
        ordering = ["name"]

    def __str__(self) -> str:
        return self.name


class CandidateQuerySet(models.QuerySet):
    """Custom QuerySet to support soft delete filtering."""
    def alive(self):
        return self.filter(is_deleted=False)


class CandidateManager(models.Manager):
    """Custom Manager for soft-delete support."""
    def get_queryset(self):
        return CandidateQuerySet(self.model, using=self._db).alive()

    def all_with_deleted(self):
        return CandidateQuerySet(self.model, using=self._db)


class Candidate(models.Model):
    """Main Candidate profile model."""
    class AvailabilityChoices(models.TextChoices):
        IMMEDIATE = "Immediate", "Immediate"
        FIFTEEN_DAYS = "15 Days", "15 Days"
        THIRTY_DAYS = "30 Days", "30 Days"
        SIXTY_DAYS = "60 Days", "60 Days"
        NINETY_DAYS = "90 Days", "90 Days"

    class StatusChoices(models.TextChoices):
        DRAFT = "Draft", "Draft"
        PROFILE_COMPLETED = "Profile Completed", "Profile Completed"
        VERIFIED = "Verified", "Verified"
        BLOCKED = "Blocked", "Blocked"

    class SourceChoices(models.TextChoices):
        SELF = "SELF", "Self Portal"
        LINKEDIN = "LINKEDIN", "LinkedIn"
        NAUKRI = "NAUKRI", "Naukri"
        UPLOAD = "UPLOAD", "CV Upload"
        REFERRAL = "REFERRAL", "Referral"
        WHATSAPP = "WHATSAPP", "WhatsApp"
        SMS = "SMS", "SMS"
        TELEGRAM = "TELEGRAM", "Telegram"
        EMAIL = "EMAIL", "Email"
        DIRECT = "DIRECT", "Direct"
        OTHER = "OTHER", "Other"

    class EmploymentTypeChoices(models.TextChoices):
        FULL_TIME = "Full Time", "Full Time"
        PART_TIME = "Part Time", "Part Time"

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        related_name="candidate_profile",
        null=True,
        blank=True,
        help_text=_("Optional associated User account"),
    )
    first_name = models.CharField(db_index=True, max_length=100)
    last_name = models.CharField(db_index=True, max_length=100)
    email = models.EmailField(blank=True, null=True, db_index=True)
    telegram_chat_id = models.CharField(
        blank=True, null=True, unique=True, db_index=True, max_length=64,
        help_text=_("Telegram chat id, set when this profile was created/claimed via the Hire AI bot."),
    )
    whatsapp_number = models.CharField(
        blank=True, null=True, unique=True, db_index=True, max_length=32,
        help_text=_("WhatsApp wa_id (sender phone number), set when this profile was created/claimed via the Hire AI WhatsApp bot."),
    )
    phone_number = models.CharField(max_length=20, validators=[validate_phone_number])
    alternate_phone_number = models.CharField(
        blank=True, null=True, max_length=20, validators=[validate_phone_number]
    )
    date_of_birth = models.DateField(blank=True, null=True)
    gender = models.CharField(blank=True, null=True, max_length=20)
    city = models.CharField(blank=True, null=True, db_index=True, max_length=100)
    state = models.CharField(blank=True, null=True, max_length=100)
    country = models.CharField(blank=True, null=True, max_length=100)
    current_address = models.TextField(blank=True, null=True)
    permanent_address = models.TextField(blank=True, null=True)
    fresher = models.BooleanField(db_index=True, default=True)
    total_experience = models.DecimalField(
        blank=True,
        null=True,
        decimal_places=1,
        max_digits=4,
        validators=[validate_non_negative],
    )
    employment_type = models.CharField(
        blank=True, null=True, db_index=True, max_length=20, choices=EmploymentTypeChoices.choices
    )
    current_company = models.CharField(blank=True, null=True, db_index=True, max_length=255)
    previous_company = models.CharField(blank=True, null=True, max_length=255)
    current_role = models.CharField(blank=True, null=True, max_length=255)
    current_ctc = models.DecimalField(
        blank=True,
        null=True,
        decimal_places=2,
        max_digits=12,
        validators=[validate_non_negative],
    )
    expected_ctc = models.DecimalField(
        blank=True,
        null=True,
        decimal_places=2,
        max_digits=12,
        validators=[validate_non_negative],
    )
    notice_period = models.IntegerField(blank=True, null=True, validators=[validate_non_negative])
    # Reference to the Notice Period master (source of truth for the profile dropdown).
    # The legacy `notice_period` integer above is kept in sync (= ref.value) for
    # existing consumers (matching, bulk import, display) during the transition.
    notice_period_ref = models.ForeignKey(
        "master_data.NoticePeriod",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="candidates",
    )
    current_location = models.CharField(blank=True, null=True, max_length=100)
    preferred_location = models.CharField(blank=True, null=True, max_length=500)
    highest_qualification = models.CharField(blank=True, null=True, max_length=255)
    university = models.CharField(blank=True, null=True, max_length=255)
    college = models.CharField(blank=True, null=True, max_length=255)
    passing_year = models.IntegerField(blank=True, null=True, validators=[validate_passing_year])
    percentage_cgpa = models.CharField(blank=True, null=True, max_length=50)
    professional_summary = models.TextField(blank=True, null=True)
    resume = models.FileField(
        blank=True, null=True, upload_to="resumes/",
        storage=resume_storage, validators=[validate_resume_file]
    )
    availability = models.CharField(
        max_length=20, choices=AvailabilityChoices.choices, default=AvailabilityChoices.IMMEDIATE
    )
    linkedin = models.URLField(blank=True, null=True)
    github = models.URLField(blank=True, null=True)
    portfolio = models.URLField(blank=True, null=True)
    personal_website = models.URLField(blank=True, null=True)
    status = models.CharField(max_length=20, choices=StatusChoices.choices, db_index=True, default=StatusChoices.DRAFT)
    source = models.CharField(max_length=20, choices=SourceChoices.choices, db_index=True,
        default=SourceChoices.OTHER, help_text="Where this candidate came from (self/linkedin/naukri/upload/referral/other).")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(db_index=True, default=True)
    is_deleted = models.BooleanField(db_index=True, default=False)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        on_delete=models.SET_NULL,
        related_name="candidates_created",
    )
    updated_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        on_delete=models.SET_NULL,
        related_name="candidates_updated",
    )
    languages = models.ManyToManyField(Language, blank=True, related_name="candidates")
    skills = models.ManyToManyField(Skill, blank=True, related_name="candidates")

    objects = CandidateManager()

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

    def __str__(self) -> str:
        return f"{self.first_name} {self.last_name}"

    def delete(self, using=None, keep_parents=False):
        """Soft delete candidate profile."""
        self.is_deleted = True
        self.is_active = False
        # `updated_by` is included so a deleter set via soft_delete_candidate()
        # is actually persisted — it powers the "Deleted By" column in the
        # admin-only Draft (soft-deleted candidates) view.
        self.save(update_fields=["is_deleted", "is_active", "updated_by", "updated_at"])

    @classmethod
    def get_for_user(cls, user):
        if not user or user.is_anonymous:
            return None
        # Try related OneToOne field
        candidate = cls.objects.filter(user=user).first()
        if candidate:
            return candidate
        # Fallback to email search (if matching Candidate exists but is unlinked)
        if user.email:
            candidate = cls.objects.filter(email__iexact=user.email).first()
            if candidate:
                if not candidate.user:
                    candidate.user = user
                    candidate.save(update_fields=["user"])
                return candidate
        # If user role is CANDIDATE, auto-create candidate profile
        if getattr(user, "role", None) == "CANDIDATE":
            candidate = cls.objects.create(
                user=user,
                first_name=user.first_name or user.email.split("@")[0],
                last_name=user.last_name or "",
                email=user.email,
                phone_number=getattr(user, "phone", "") or "0000000000",
                source=cls.SourceChoices.SELF,
                created_by=user,
            )
            return candidate
        return None


class CandidateAttachment(models.Model):
    """OpenCATS-style attachment: multiple files per candidate with metadata,
    upload history, extracted résumé text (for full-text search) and per-file
    private storage. The active résumé is the one with is_primary=True."""

    class Kind(models.TextChoices):
        RESUME = "resume", "Résumé"
        COVER_LETTER = "cover_letter", "Cover Letter"
        OTHER = "other", "Other"

    candidate = models.ForeignKey(
        Candidate, related_name="attachments", on_delete=models.CASCADE
    )
    file = models.FileField(upload_to=attachment_path, storage=resume_storage)
    original_filename = models.CharField(max_length=255, blank=True, default="")
    content_type = models.CharField(max_length=100, blank=True, default="")
    size = models.PositiveIntegerField(default=0)
    kind = models.CharField(max_length=20, choices=Kind.choices, default=Kind.RESUME, db_index=True)
    is_primary = models.BooleanField(default=False, db_index=True)
    extracted_text = models.TextField(blank=True, default="")
    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True,
        on_delete=models.SET_NULL, related_name="uploaded_attachments",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "candidate_attachments"
        ordering = ["-is_primary", "-created_at"]

    def __str__(self):
        return f"{self.original_filename or self.file.name} ({self.candidate_id})"


class CandidateDocument(models.Model):
    """Model to store verification documents for a candidate."""
    class VerificationStatus(models.TextChoices):
        PENDING = "Pending", "Pending"
        VERIFIED = "Verified", "Verified"
        REJECTED = "Rejected", "Rejected"

    DOCUMENT_TYPE_CHOICES = [
        ("Aadhar Card", "Aadhar Card"),
        ("PAN Card", "PAN Card"),
        ("Passport", "Passport"),
        ("Driving License", "Driving License"),
        ("Degree Certificate", "Degree Certificate"),
        ("Experience Letter", "Experience Letter"),
        ("Offer Letter", "Offer Letter"),
    ]

    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="documents")
    document_type = models.CharField(max_length=50, choices=DOCUMENT_TYPE_CHOICES)
    file = models.FileField(upload_to="verification_documents/", validators=[validate_document_file])
    verification_status = models.CharField(
        max_length=20,
        choices=VerificationStatus.choices,
        db_index=True,
        default=VerificationStatus.PENDING,
    )

    class Meta:
        db_table = "candidate_documents"
        ordering = ["id"]

    def __str__(self) -> str:
        return f"{self.document_type} - {self.candidate.first_name}"


class CandidateProject(models.Model):
    """Model to store projects candidate worked on."""
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="projects")
    project_name = models.CharField(max_length=255)
    description = models.TextField(blank=True, null=True)
    technologies_used = models.TextField(
        blank=True, null=True, help_text=_("Comma separated technologies list")
    )
    duration = models.CharField(blank=True, null=True, max_length=100)
    role = models.CharField(blank=True, null=True, max_length=100)

    class Meta:
        db_table = "candidate_projects"
        ordering = ["id"]

    def __str__(self) -> str:
        return f"{self.project_name} - {self.candidate.first_name}"


class CandidateReference(models.Model):
    """Model to store candidate references."""
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="references")
    name = models.CharField(max_length=255)
    company = models.CharField(blank=True, null=True, max_length=255)
    designation = models.CharField(blank=True, null=True, max_length=255)
    email = models.EmailField(blank=True, null=True, max_length=254)
    phone = models.CharField(blank=True, null=True, max_length=20)
    relationship = models.CharField(blank=True, null=True, max_length=100)

    class Meta:
        db_table = "candidate_references"
        ordering = ["id"]

    def __str__(self) -> str:
        return f"{self.name} - {self.candidate.first_name}"


class CandidateEducation(models.Model):
    """Model to store candidate education details."""
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="educations")
    degree_name = models.CharField(max_length=255)
    field_of_study = models.CharField(blank=True, null=True, max_length=255)
    institution_name = models.CharField(max_length=255)
    passing_year = models.IntegerField()
    percentage_cgpa = models.CharField(blank=True, null=True, max_length=50)

    class Meta:
        db_table = "candidate_education"
        ordering = ["-passing_year"]

    def __str__(self) -> str:
        return f"{self.degree_name} - {self.candidate.first_name}"


class CandidateExperience(models.Model):
    """Model to store candidate work experience details."""
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="experiences")
    company_name = models.CharField(max_length=255)
    role = models.CharField(max_length=255)
    joining_date = models.DateField()
    last_working_date = models.DateField(blank=True, null=True)
    is_current_company = models.BooleanField(default=False)
    current_ctc = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=12)
    expected_ctc = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=12)
    notice_period = models.IntegerField(blank=True, null=True)
    achievements = models.TextField(blank=True, null=True)
    responsibilities = models.TextField(blank=True, null=True)
    reason_for_leaving = models.TextField(blank=True, null=True)

    class Meta:
        db_table = "candidate_experience"
        ordering = ["-joining_date"]

    def __str__(self) -> str:
        return f"{self.role} at {self.company_name} - {self.candidate.first_name}"


class NotificationLog(models.Model):
    """Log of every notification sent (or attempted) to a candidate."""
    class Channel(models.TextChoices):
        EMAIL = "EMAIL", "Email"
        WHATSAPP = "WHATSAPP", "WhatsApp"
        SMS = "SMS", "SMS"

    class Status(models.TextChoices):
        SENT = "SENT", "Sent"
        FAILED = "FAILED", "Failed"

    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="notifications")
    channel = models.CharField(max_length=10, choices=Channel.choices)
    status = models.CharField(max_length=10, choices=Status.choices)
    subject = models.CharField(max_length=255, blank=True, default="")
    message = models.TextField(blank=True, default="")
    error = models.TextField(blank=True, default="")
    sent_by = models.ForeignKey("users.User", null=True, blank=True, on_delete=models.SET_NULL)
    created_at = models.DateTimeField(auto_now_add=True)

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

    def __str__(self) -> str:
        return f"{self.channel} to {self.candidate_id} - {self.status}"


class CandidateComment(models.Model):
    """Recruiter notes on a candidate — e.g. call outcomes, screening remarks."""
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name="comments")
    comment = models.TextField()
    created_by = models.ForeignKey("users.User", null=True, blank=True, on_delete=models.SET_NULL, related_name="candidate_comments")
    created_at = models.DateTimeField(auto_now_add=True)

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

    def __str__(self) -> str:
        return f"Comment on {self.candidate_id} by {self.created_by_id}"


class EmailOptOut(models.Model):
    """OUT-007: email addresses that have unsubscribed from outreach."""
    email = models.EmailField(unique=True, db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "email_opt_outs"

    def __str__(self):
        return self.email
