"""Tracer study launcher.

PRD 3.2.5 asks for tracer studies ("where are alumni working, how did their
training help?"). We reuse the existing :mod:`apps.mel.feedback` TracerStudy
primitive rather than rebuilding survey infra inside the alumni module.
"""
from __future__ import annotations

import logging
from typing import Any

from django.db import transaction
from django.utils import timezone
from django.utils.text import slugify

logger = logging.getLogger(__name__)


@transaction.atomic
def launch_tracer_survey(cohort_filter: dict[str, Any]):
    """Create a ``TracerStudy`` for a cohort and notify matching alumni.

    ``cohort_filter`` accepts any of:
      - ``graduation_year`` (int) — match on Degree.graduated_on year
      - ``programme_name`` (str, icontains)
      - ``country`` (str, ISO)
      - ``name`` (str, optional survey title override)
    """
    from apps.alumni.profiles.models import AlumniProfile
    from apps.core.notifications.models import Notification
    from apps.core.notifications.services import send_notification
    from apps.mel.feedback.models import TracerStudy

    year = cohort_filter.get("graduation_year")
    programme = cohort_filter.get("programme_name")
    country = cohort_filter.get("country")
    name = cohort_filter.get("name") or f"Tracer study — {timezone.now():%Y-%m}"

    slug_base = slugify(name)[:100] or f"tracer-{timezone.now():%Y%m%d}"
    slug = slug_base
    n = 2
    while TracerStudy.objects.filter(slug=slug).exists():
        slug = f"{slug_base}-{n}"
        n += 1

    description_parts = []
    if year:
        description_parts.append(f"cohort {year}")
    if programme:
        description_parts.append(f"programme '{programme}'")
    if country:
        description_parts.append(f"country {country}")
    target = "Alumni" + (" — " + ", ".join(description_parts) if description_parts else "")

    study = TracerStudy.objects.create(
        name=name,
        slug=slug,
        description="Post-graduation outcomes survey.",
        target_population=target,
    )

    qs = AlumniProfile.objects.all().select_related("user")
    if year:
        qs = qs.filter(degrees__graduated_on__year=year).distinct()
    if programme:
        qs = qs.filter(degrees__programme_name__icontains=programme).distinct()
    if country:
        qs = qs.filter(user__profile__country__iexact=country)

    invited = 0
    for profile in qs:
        try:
            send_notification(
                profile.user,
                f"You are invited to the tracer study: {study.name}.",
                verb=Notification.Verb.ALUMNI_TRACER_SURVEY_INVITED,
            )
            invited += 1
        except Exception:  # pragma: no cover - defensive
            logger.exception(
                "alumni.tracer invite failed profile=%s study=%s",
                profile.pk,
                study.pk,
            )
    logger.info("alumni.tracer launched study=%s invited=%s", study.slug, invited)
    return study


@transaction.atomic
def launch_employer_feedback(
    profile,
    *,
    employer_email: str,
    employer_name: str = "",
):
    """Invite an alumna/us's employer to fill a short curriculum-feedback survey.

    Reuses :class:`apps.mel.feedback.TracerStudy` so responses land in the
    same M&EL pipeline as cohort tracer studies. Returns the
    :class:`EmployerFeedbackInvitation` row; idempotent on
    (profile, employer_email).
    """
    from django.urls import reverse

    from apps.alumni.profiles.models import EmployerFeedbackInvitation
    from apps.core.notifications.models import Notification
    from apps.core.notifications.services import send_notification
    from apps.mel.feedback.models import TracerStudy

    name = f"Employer feedback — {profile.display_name}"
    slug_base = slugify(name)[:100] or f"employer-feedback-{timezone.now():%Y%m%d}"
    slug = slug_base
    n = 2
    while TracerStudy.objects.filter(slug=slug).exists():
        slug = f"{slug_base}-{n}"
        n += 1
    study = TracerStudy.objects.create(
        name=name,
        slug=slug,
        description="Employer feedback on RUFORUM training relevance.",
        target_population="Employers — programme curriculum feedback",
    )
    invitation, created = EmployerFeedbackInvitation.objects.get_or_create(
        profile=profile,
        employer_email=employer_email,
        defaults={
            "employer_name": employer_name,
            "study": study,
        },
    )
    if not created:
        # Already invited — keep the original invitation/token, drop the
        # newly-created study so we don't leak orphan rows.
        study.delete()
    if created:
        try:
            from django.conf import settings

            base = getattr(settings, "PUBLIC_APP_BASE_URL", "").rstrip("/")
            path = reverse("alumni_profiles:employer_feedback_form", args=[invitation.token])
            link = f"{base}{path}" if base else path
            send_notification(
                profile.user,
                f"Employer feedback invite sent to {employer_email}.",
                verb=Notification.Verb.ALUMNI_EMPLOYER_FEEDBACK_INVITED,
                email_context={
                    "subject": "Employer feedback invitation sent",
                    "body_html": (
                        f"<p>We sent {employer_email} a short curriculum-feedback "
                        f"survey about your time at RUFORUM. They can complete it at:</p>"
                        f"<p><a href=\"{link}\">{link}</a></p>"
                    ),
                },
            )
        except Exception:  # pragma: no cover - defensive
            logger.exception("alumni.employer_feedback notify failed invitation=%s", invitation.pk)
    return invitation
