from __future__ import annotations

from django.db import models

from apps.alumni.profiles.models import AlumniProfile
from apps.core.storage.paths import upload_to_alumni_certificates


class MilestoneType(models.TextChoices):
    PROMOTION = "promotion", "Promotion"
    NEW_JOB = "new_job", "New job"
    AWARD = "award", "Award"
    PUBLICATION = "publication", "Publication"
    GRANT = "grant", "Grant"
    PATENT = "patent", "Patent"
    LEADERSHIP = "leadership", "Leadership role"
    SPEAKING = "speaking", "Speaking engagement"
    GRADUATION = "graduation", "Graduation"
    RECOGNITION = "recognition", "Recognition"
    OTHER = "other", "Other"


class MilestoneVisibility(models.TextChoices):
    PUBLIC = "public", "Public"
    NETWORK = "network", "Alumni network only"
    PRIVATE = "private", "Private"


class CareerMilestone(models.Model):
    profile = models.ForeignKey(
        AlumniProfile,
        on_delete=models.CASCADE,
        related_name="milestones",
    )
    milestone_type = models.CharField(
        max_length=24,
        choices=MilestoneType.choices,
        default=MilestoneType.OTHER,
    )
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    occurred_on = models.DateField()
    url = models.URLField(blank=True)
    evidence_file = models.FileField(
        upload_to=upload_to_alumni_certificates,
        blank=True,
        null=True,
    )
    visibility = models.CharField(
        max_length=16,
        choices=MilestoneVisibility.choices,
        default=MilestoneVisibility.PUBLIC,
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-occurred_on"]
        indexes = [
            models.Index(fields=["profile", "occurred_on"]),
        ]

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


class PublicationTypeChoice(models.TextChoices):
    JOURNAL = "journal-article", "Journal article"
    BOOK = "book", "Book"
    CHAPTER = "book-chapter", "Book chapter"
    CONFERENCE = "conference-paper", "Conference paper"
    PREPRINT = "preprint", "Preprint"
    REPORT = "report", "Report"
    OTHER = "other", "Other"


class ResearchOutput(models.Model):
    """ORCID-synced research work (one per ORCID 'put-code')."""

    profile = models.ForeignKey(
        AlumniProfile,
        on_delete=models.CASCADE,
        related_name="research_outputs",
    )
    put_code = models.CharField(max_length=32, help_text="ORCID work put-code")
    title = models.CharField(max_length=500)
    publication_type = models.CharField(
        max_length=32,
        choices=PublicationTypeChoice.choices,
        default=PublicationTypeChoice.OTHER,
    )
    doi = models.CharField(max_length=128, blank=True)
    year = models.PositiveSmallIntegerField(null=True, blank=True)
    payload = models.JSONField(default=dict, blank=True)
    last_synced_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-year", "title"]
        constraints = [
            models.UniqueConstraint(
                fields=["profile", "put_code"],
                name="uniq_research_output_per_profile_putcode",
            ),
        ]

    def __str__(self):
        return self.title[:80]


class ImpactMetric(models.TextChoices):
    CITATIONS = "citations", "Citations"
    FUNDING_SECURED_USD = "funding_secured_usd", "Funding secured (USD)"
    JOBS_CREATED = "jobs_created", "Jobs created"
    STUDENTS_SUPERVISED = "students_supervised", "Students supervised"
    POLICIES_INFLUENCED = "policies_influenced", "Policies influenced"
    MEDIA_MENTIONS = "media_mentions", "Media mentions"


class ImpactSource(models.TextChoices):
    SELF = "self", "Self-reported"
    AUTO = "auto", "Automated aggregation"
    ORCID = "orcid", "Synced from ORCID"


class ImpactRecord(models.Model):
    profile = models.ForeignKey(
        AlumniProfile,
        on_delete=models.CASCADE,
        related_name="impact_records",
    )
    metric = models.CharField(max_length=32, choices=ImpactMetric.choices)
    value = models.DecimalField(max_digits=16, decimal_places=2)
    period_label = models.CharField(
        max_length=16,
        help_text="Reporting period, e.g. '2026' or '2026-Q1'.",
    )
    source = models.CharField(
        max_length=16,
        choices=ImpactSource.choices,
        default=ImpactSource.SELF,
    )
    recorded_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-period_label", "metric"]
        constraints = [
            models.UniqueConstraint(
                fields=["profile", "metric", "period_label"],
                name="uniq_impact_per_profile_metric_period",
            ),
        ]

    def __str__(self):
        return f"{self.profile_id} {self.metric} {self.period_label}"


class ImpactSnapshot(models.Model):
    """Monthly aggregate for donor dashboards.

    Snapshots protect donor-facing numbers from live-aggregation drift —
    running the snapshot task again for the same period is idempotent.
    """

    period_label = models.CharField(max_length=16, unique=True)
    generated_at = models.DateTimeField(auto_now=True)
    total_alumni = models.PositiveIntegerField(default=0)
    active_mentorships = models.PositiveIntegerField(default=0)
    total_publications = models.PositiveIntegerField(default=0)
    total_citations = models.PositiveIntegerField(default=0)
    funding_secured_usd = models.DecimalField(
        max_digits=18, decimal_places=2, default=0
    )
    breakdown = models.JSONField(default=dict, blank=True)

    class Meta:
        ordering = ["-period_label"]

    def __str__(self):
        return f"ImpactSnapshot<{self.period_label}>"


class OrcidSyncLog(models.Model):
    profile = models.OneToOneField(
        AlumniProfile,
        on_delete=models.CASCADE,
        related_name="orcid_sync_log",
    )
    orcid_id = models.CharField(max_length=19)
    last_attempt_at = models.DateTimeField(null=True, blank=True)
    last_success_at = models.DateTimeField(null=True, blank=True)
    last_error = models.TextField(blank=True)
    consecutive_failures = models.PositiveIntegerField(default=0)
    works_imported_count = models.PositiveIntegerField(default=0)

    def __str__(self):
        return f"OrcidSyncLog<{self.orcid_id}>"
