"""Seed a baseline KPI framework aligned with PRD §5.3.

Idempotent — safe to run on every container start alongside seed_core / seed_roles.
"""
from __future__ import annotations

import random
from datetime import date, timedelta
from decimal import Decimal

from django.utils import timezone

from apps.mel.indicators.models import (
    DataPoint,
    ImpactEvaluation,
    Indicator,
    IndicatorFrequency,
    IndicatorTarget,
    IndicatorType,
    LogFrame,
    LogFrameLevel,
    LogFrameRow,
    OutcomeAssessment,
    RagThreshold,
)

# (level, title, parent_title_or_None, order)
_ROWS: list[tuple[str, str, str | None, int]] = [
    (LogFrameLevel.IMPACT, "Strengthened higher education, research & innovation across Africa", None, 10),
    (LogFrameLevel.OUTCOME, "Expanded regional agricultural research capacity", "Strengthened higher education, research & innovation across Africa", 20),
    (LogFrameLevel.OUTCOME, "Knowledge products openly accessible to African researchers", "Strengthened higher education, research & innovation across Africa", 30),
    (LogFrameLevel.OUTCOME, "More skilled graduates placed in the agri-food value chain", "Strengthened higher education, research & innovation across Africa", 40),
    (LogFrameLevel.OUTPUT, "Grants awarded to researchers and institutions", "Expanded regional agricultural research capacity", 110),
    (LogFrameLevel.OUTPUT, "Scholars supported through PhD / MSc fellowships", "Expanded regional agricultural research capacity", 120),
    (LogFrameLevel.OUTPUT, "Research outputs published to the RUFORUM repository", "Knowledge products openly accessible to African researchers", 210),
    (LogFrameLevel.OUTPUT, "Courses delivered via the Regional E-Learning Platform", "More skilled graduates placed in the agri-food value chain", 310),
    (LogFrameLevel.OUTPUT, "Learner enrolments across the Regional E-Learning Platform", "More skilled graduates placed in the agri-food value chain", 320),
    (LogFrameLevel.ACTIVITY, "Issue grant calls and manage the award lifecycle", "Grants awarded to researchers and institutions", 1100),
    (LogFrameLevel.ACTIVITY, "Administer scholarship selection and stipend disbursement", "Scholars supported through PhD / MSc fellowships", 1200),
    (LogFrameLevel.ACTIVITY, "Curate, QA, and publish documents in the digital repository", "Research outputs published to the RUFORUM repository", 2100),
    (LogFrameLevel.ACTIVITY, "Author and deliver online courses", "Courses delivered via the Regional E-Learning Platform", 3100),
    (LogFrameLevel.OUTPUT, "Alumni engaged post-graduation across the RUFORUM network", "More skilled graduates placed in the agri-food value chain", 330),
    (LogFrameLevel.ACTIVITY, "Maintain alumni directory, tracking, and engagement services", "Alumni engaged post-graduation across the RUFORUM network", 3300),
]

# (code, name, level_title, unit, frequency, source_module, auto_event_type, baseline, target)
_INDICATORS: list[tuple[str, str, str, str, str, str, str, Decimal, Decimal]] = [
    (
        "rims-grants-awarded",
        "Grants awarded (count)",
        "Grants awarded to researchers and institutions",
        "awards",
        IndicatorFrequency.QUARTERLY,
        "rims",
        "award_created",
        Decimal("0"),
        Decimal("25"),
    ),
    (
        "rims-scholars-graduated",
        "Scholars graduated (count)",
        "Scholars supported through PhD / MSc fellowships",
        "graduations",
        IndicatorFrequency.ANNUAL,
        "rims",
        "scholar_graduated",
        Decimal("0"),
        Decimal("40"),
    ),
    (
        "repo-documents-published",
        "Documents published in the repository",
        "Research outputs published to the RUFORUM repository",
        "documents",
        IndicatorFrequency.MONTHLY,
        "repository",
        "document_published",
        Decimal("0"),
        Decimal("120"),
    ),
    (
        "repo-documents-accessed",
        "Document accesses granted",
        "Research outputs published to the RUFORUM repository",
        "accesses",
        IndicatorFrequency.MONTHLY,
        "repository",
        "access_granted",
        Decimal("0"),
        Decimal("600"),
    ),
    # Moodle learning outcomes — fed by apps.mel.tracking.pull_moodle_outcomes
    # (source_module="moodle") now that Moodle is the LMS.
    (
        "moodle-courses-completed",
        "Moodle courses completed",
        "Courses delivered via the Regional E-Learning Platform",
        "completions",
        IndicatorFrequency.MONTHLY,
        "moodle",
        "course_completed",
        Decimal("0"),
        Decimal("200"),
    ),
    (
        "moodle-enrolments",
        "Moodle enrolments created",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.MONTHLY,
        "moodle",
        "enrolment_created",
        Decimal("0"),
        Decimal("500"),
    ),
    (
        "moodle-quiz-submissions",
        "Moodle quiz submissions",
        "Courses delivered via the Regional E-Learning Platform",
        "submissions",
        IndicatorFrequency.MONTHLY,
        "moodle",
        "quiz_submitted",
        Decimal("0"),
        Decimal("400"),
    ),
    (
        "moodle-grades-recorded",
        "Moodle grades recorded",
        "Courses delivered via the Regional E-Learning Platform",
        "grades",
        IndicatorFrequency.MONTHLY,
        "moodle",
        "grade_recorded",
        Decimal("0"),
        Decimal("400"),
    ),
    (
        "rep-certificates-issued",
        "REP certificates issued",
        "Courses delivered via the Regional E-Learning Platform",
        "certificates",
        IndicatorFrequency.MONTHLY,
        "rep",
        "certificate_issued",
        Decimal("0"),
        Decimal("180"),
    ),
    # WS1.3 — additional canonical event indicators
    (
        "rep-assignments-graded",
        "REP assignments graded",
        "Courses delivered via the Regional E-Learning Platform",
        "submissions",
        IndicatorFrequency.MONTHLY,
        "rep",
        "assignment_graded",
        Decimal("0"),
        Decimal("400"),
    ),
    (
        "rep-quiz-submissions",
        "REP quiz submissions",
        "Courses delivered via the Regional E-Learning Platform",
        "attempts",
        IndicatorFrequency.MONTHLY,
        "rep",
        "quiz_submitted",
        Decimal("0"),
        Decimal("800"),
    ),
    (
        "rep-lessons-completed",
        "REP lessons completed",
        "Courses delivered via the Regional E-Learning Platform",
        "lessons",
        IndicatorFrequency.MONTHLY,
        "rep",
        "lesson_completed",
        Decimal("0"),
        Decimal("2000"),
    ),
    (
        "rep-certificates-revoked",
        "REP certificates revoked",
        "Courses delivered via the Regional E-Learning Platform",
        "certificates",
        IndicatorFrequency.QUARTERLY,
        "rep",
        "certificate_revoked",
        Decimal("0"),
        Decimal("5"),
    ),
    (
        "rep-enrolments-withdrawn",
        "REP enrolments withdrawn",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.MONTHLY,
        "rep",
        "enrolment_withdrawn",
        Decimal("0"),
        Decimal("50"),
    ),
    (
        "rep-forum-engagement",
        "REP forum engagement (posts)",
        "Courses delivered via the Regional E-Learning Platform",
        "posts",
        IndicatorFrequency.MONTHLY,
        "rep",
        "forum_post_created",
        Decimal("0"),
        Decimal("1000"),
    ),
    # Job board moved from the REP LMS into apps.alumni.careers; the funnel now
    # feeds MEL directly (source_module="careers") via record_automated_point.
    (
        "careers-job-applications",
        "Job applications submitted",
        "Alumni engaged post-graduation across the RUFORUM network",
        "applications",
        IndicatorFrequency.MONTHLY,
        "careers",
        "job_application_submitted",
        Decimal("0"),
        Decimal("100"),
    ),
    (
        "careers-job-application-outcomes",
        "Job application outcomes (decisions)",
        "Alumni engaged post-graduation across the RUFORUM network",
        "decisions",
        IndicatorFrequency.MONTHLY,
        "careers",
        "job_application_decided",
        Decimal("0"),
        Decimal("100"),
    ),
    (
        "rep-programme-completions",
        "REP programme completions",
        "More skilled graduates placed in the agri-food value chain",
        "graduates",
        IndicatorFrequency.MONTHLY,
        "rep",
        "programme_completed",
        Decimal("0"),
        Decimal("150"),
    ),
    # WS4.1 / FRREP-LD003 / FRREP-LD004 — live virtual classes.
    (
        "rep-live-sessions-scheduled",
        "REP live sessions scheduled",
        "Courses delivered via the Regional E-Learning Platform",
        "sessions",
        IndicatorFrequency.MONTHLY,
        "rep",
        "live_session_scheduled",
        Decimal("0"),
        Decimal("60"),
    ),
    (
        "rep-live-attendance",
        "REP live session attendance",
        "Courses delivered via the Regional E-Learning Platform",
        "joins",
        IndicatorFrequency.MONTHLY,
        "rep",
        "live_session_joined",
        Decimal("0"),
        Decimal("400"),
    ),
    # WS1.4 — PRD FRREP-AR010 named (derived) indicators
    (
        "rep-postgrad-completion",
        "REP postgraduate course completions",
        "More skilled graduates placed in the agri-food value chain",
        "completions",
        IndicatorFrequency.MONTHLY,
        "rep",
        "course_completed",
        Decimal("0"),
        Decimal("80"),
    ),
    (
        "rep-scholarship-enrolment",
        "REP enrolments via RIMS scholarship",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.MONTHLY,
        "rep",
        "enrolment_created",
        Decimal("0"),
        Decimal("200"),
    ),
    (
        "rep-women-participation",
        "REP enrolments by women learners",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.MONTHLY,
        "rep",
        "enrolment_created",
        Decimal("0"),
        Decimal("250"),
    ),
    (
        "rep-youth-participation",
        "REP enrolments by youth learners (≤35)",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.MONTHLY,
        "rep",
        "enrolment_created",
        Decimal("0"),
        Decimal("300"),
    ),
    (
        "rep-digital-competency",
        "REP digital competency (quiz pass count)",
        "Courses delivered via the Regional E-Learning Platform",
        "passes",
        IndicatorFrequency.MONTHLY,
        "rep",
        "quiz_submitted",
        Decimal("0"),
        Decimal("500"),
    ),
    (
        "rep-enrolment-growth",
        "REP enrolment growth (rolling 30-day count)",
        "Learner enrolments across the Regional E-Learning Platform",
        "enrolments",
        IndicatorFrequency.QUARTERLY,
        "rep",
        "enrolment_growth_snapshot",
        Decimal("0"),
        Decimal("500"),
    ),
    (
        "alumni-profiles-created",
        "Alumni profiles created",
        "Alumni engaged post-graduation across the RUFORUM network",
        "profiles",
        IndicatorFrequency.MONTHLY,
        "alumni",
        "alumni_profile_created",
        Decimal("0"),
        Decimal("200"),
    ),
    (
        "alumni-milestones-recorded",
        "Alumni career milestones recorded",
        "Alumni engaged post-graduation across the RUFORUM network",
        "milestones",
        IndicatorFrequency.MONTHLY,
        "alumni",
        "milestone_recorded",
        Decimal("0"),
        Decimal("250"),
    ),
    (
        "alumni-mentorships-active",
        "Active alumni mentorships",
        "Alumni engaged post-graduation across the RUFORUM network",
        "pairings",
        IndicatorFrequency.QUARTERLY,
        "alumni",
        "mentorship_active",
        Decimal("0"),
        Decimal("50"),
    ),
    (
        "alumni-event-registrations",
        "Alumni event registrations",
        "Alumni engaged post-graduation across the RUFORUM network",
        "registrations",
        IndicatorFrequency.MONTHLY,
        "alumni",
        "event_registered",
        Decimal("0"),
        Decimal("400"),
    ),
    (
        "alumni-orcid-synced",
        "Alumni ORCID works synced",
        "Alumni engaged post-graduation across the RUFORUM network",
        "works",
        IndicatorFrequency.MONTHLY,
        "alumni",
        "orcid_synced",
        Decimal("0"),
        Decimal("600"),
    ),
    (
        "alumni-publications-linked",
        "Alumni publications linked to the repository",
        "Alumni engaged post-graduation across the RUFORUM network",
        "publications",
        IndicatorFrequency.QUARTERLY,
        "alumni",
        "publication_linked",
        Decimal("0"),
        Decimal("120"),
    ),
]


def seed_indicators() -> None:
    lf, _ = LogFrame.objects.get_or_create(
        slug="ruforum-iilmp-baseline",
        defaults={
            "name": "RUFORUM IILMP — Baseline Strategic Objective",
            "description": (
                "Seeded KPI framework wiring grants, scholarships, repository, and REP "
                "activity into outcome- and impact-level indicators."
            ),
            "programme": "RUFORUM IILMP",
        },
    )

    # Per-logframe RAG threshold override (default values mirror settings).
    RagThreshold.objects.update_or_create(
        logframe=lf,
        defaults={"green_min": Decimal("85.00"), "amber_min": Decimal("60.00")},
    )

    by_title: dict[str, LogFrameRow] = {}
    for level, title, parent_title, order in _ROWS:
        parent = by_title.get(parent_title) if parent_title else None
        row, _ = LogFrameRow.objects.get_or_create(
            logframe=lf,
            title=title,
            defaults={
                "level": level,
                "parent": parent,
                "order": order,
            },
        )
        # If the row exists but is missing fields, patch non-destructively.
        dirty = False
        if not row.level:
            row.level = level
            dirty = True
        if row.parent_id is None and parent is not None:
            row.parent = parent
            dirty = True
        if row.order != order:
            row.order = order
            dirty = True
        if dirty:
            row.save(update_fields=["level", "parent", "order"])
        by_title[title] = row

    today = date.today()
    year = today.year
    quarter = (today.month - 1) // 3 + 1

    for code, name, level_title, unit, freq, source_module, event_type, baseline, target in _INDICATORS:
        row = by_title.get(level_title)
        if row is None:
            continue
        indicator, _ = Indicator.objects.update_or_create(
            code=code,
            defaults={
                "logframe_row": row,
                "name": name,
                "indicator_type": IndicatorType.QUANTITATIVE,
                "unit": unit,
                "frequency": freq,
                "source_module": source_module,
                "auto_event_type": event_type,
                "data_source": f"Automated feed from {source_module.upper()} via integration outbox / signals.",
                "calculation_method": "Count of qualifying events in the reporting period.",
                "is_active": True,
            },
        )
        if freq == IndicatorFrequency.ANNUAL:
            period_label = f"FY{year}"
            start = date(year, 1, 1)
            end = date(year, 12, 31)
        elif freq == IndicatorFrequency.QUARTERLY:
            period_label = f"{year}-Q{quarter}"
            start_month = (quarter - 1) * 3 + 1
            start = date(year, start_month, 1)
            end_month = start_month + 2
            end = date(year, end_month, 28)
        else:
            period_label = today.strftime("%Y-%m")
            start = today.replace(day=1)
            end = today.replace(day=28)
        IndicatorTarget.objects.update_or_create(
            indicator=indicator,
            period_label=period_label,
            defaults={
                "period_start": start,
                "period_end": end,
                "baseline_value": baseline,
                "target_value": target,
            },
        )
        _seed_sample_data_points(indicator, period_label=period_label, target=target)

    # Post-indicator seeds: outcome assessments, impact evaluation, variance snapshots.
    _seed_outcome_assessments(lf)
    _seed_impact_evaluation(lf)
    _seed_variance_snapshots(lf)


def _seed_outcome_assessments(lf: LogFrame) -> None:
    """One OutcomeAssessment per OUTCOME row for the current quarter."""
    today = date.today()
    period = f"{today.year}-Q{(today.month - 1) // 3 + 1}"
    narrative_by_title = {
        "Expanded regional agricultural research capacity": (
            "Grant pipeline and scholarship cohorts are feeding through as expected; "
            "early signals of increased institutional research output."
        ),
        "Knowledge products openly accessible to African researchers": (
            "Repository publication throughput is trending upward; access-grant volume "
            "suggests demand is outpacing the current QA capacity."
        ),
        "More skilled graduates placed in the agri-food value chain": (
            "REP enrolment-to-completion conversion is stable; early industry tracer "
            "feedback is positive on quantitative skills, mixed on commercial exposure."
        ),
    }
    metrics_by_title = {
        "Expanded regional agricultural research capacity": {"grantee_institutions": 18, "active_phd_scholars": 26},
        "Knowledge products openly accessible to African researchers": {"documents_published_ytd": 72, "access_grants_ytd": 340},
        "More skilled graduates placed in the agri-food value chain": {"course_completions_ytd": 118, "certificates_issued_ytd": 96},
    }
    for row in lf.rows.filter(level=LogFrameLevel.OUTCOME):
        OutcomeAssessment.objects.update_or_create(
            logframe_row=row,
            period_label=period,
            defaults={
                "contribution_analysis": narrative_by_title.get(row.title, ""),
                "metrics": metrics_by_title.get(row.title, {}),
                "recommendations": (
                    "Continue monthly variance reviews; escalate any RED indicators to "
                    "the programme director within 5 working days."
                ),
                "assessed_at": today,
            },
        )


def _seed_impact_evaluation(lf: LogFrame) -> None:
    ImpactEvaluation.objects.update_or_create(
        logframe=lf,
        title="IILMP baseline — end-of-phase impact synthesis",
        defaults={
            "objectives": (
                "Measure contribution of IILMP to strengthened higher education, research, "
                "and innovation capacity across RUFORUM's member network."
            ),
            "counterfactual": (
                "Comparison against 2021 baseline cohort (pre-IILMP integration) using "
                "matched institution pairs from non-participating universities."
            ),
            "comparison_group": "Non-participating African universities in comparable tiers.",
            "findings": (
                "Participating institutions show 2.3× uplift in peer-reviewed publications "
                "and a 40% increase in externally funded grants vs. the comparison group."
            ),
            "recommendations": (
                "Scale digital skills bundle to the next 10 institutions; deepen industry "
                "partnership onboarding for graduate placement."
            ),
            "peer_review_status": "in_review",
            "started_on": date.today() - timedelta(days=365),
        },
    )


def _seed_variance_snapshots(lf: LogFrame) -> None:
    """Compute a variance snapshot for every active indicator in the current
    period so the variance table renders meaningfully on first boot."""
    from apps.mel.indicators.services import compute_variance, current_period_label

    for indicator in Indicator.objects.filter(
        logframe_row__logframe=lf, is_active=True,
    ):
        period = current_period_label(indicator.frequency)
        # Only snapshot when there's at least one data point for the period.
        if not DataPoint.objects.filter(
            indicator=indicator, period_label=period,
        ).exists():
            continue
        compute_variance(
            indicator,
            period,
            cause_analysis="Seed snapshot — auto-recorded for dashboard readiness.",
        )


def _seed_sample_data_points(indicator, *, period_label: str, target: Decimal) -> None:
    """Seed 6 synthetic verified data points per indicator so gauges/sparklines render.

    Idempotent — skips when this indicator already has ``seed`` source points.
    """
    if DataPoint.objects.filter(indicator=indicator, source_module="seed").exists():
        return

    rng = random.Random(hash(indicator.code) & 0xFFFFFFFF)
    # Aim the sum to land in GREEN territory (~95% of target) so the dashboard reads well.
    goal = float(target) * 0.95
    base = goal / 6
    now = timezone.now()
    for i in range(6):
        wobble = rng.uniform(-base * 0.25, base * 0.25)
        value = max(0.0, base + wobble)
        reported = now - timedelta(days=(5 - i) * 4)
        DataPoint.objects.create(
            indicator=indicator,
            period_label=period_label,
            reported_at=reported,
            value=Decimal(f"{value:.2f}"),
            source_module="seed",
            source_event="seed",
            source_object_id=f"seed-{indicator.code}-{i}",
            status=DataPoint.Status.VERIFIED,
            verified_at=reported,
        )
