"""MEL Progress-Reporting dashboard for Program Coordinators / Implementers.

The M&E SRS (§4.4.3 Progress Reporting, Table 65) gives field roles a narrow
job: *submit implementation data for the activities/indicators under their
responsibility*, then track each submission as the M&E Officer validates it.
"Program Implementer" is not a distinct ``UserRole`` — the SRS models it as
whoever is assigned as ``Indicator.responsible`` — so this dashboard lights up
for two overlapping populations:

* users whose role is in ``MEL_IMPLEMENTER_ROLES`` (Program Coordinator, …), and
* any authenticated user who is the responsible officer on an active indicator
  (the implicit Program Implementer, mirroring ``DataEntryView.dispatch``).

M&E Officers are deliberately excluded — they already get the richer officer
dashboard (``mel_widgets``) and the validation queue, so we don't stack a
second, narrower persona on top.

Only surfaces a field role can actually open are linked from here:
``mel_indicators:data_entry`` (submit — reachable only when the user is
responsible on ≥1 active indicator) and ``mel_indicators:validation_queue``
(their own submissions, reachable by any authenticated user). Officer-only
pages (indicator register, logframes, reports) are intentionally not linked.
"""
from __future__ import annotations

from django.urls import reverse

from apps.core.dashboard.base import (
    ZONE_ACTIONS,
    ZONE_KPI,
    ZONE_PRIMARY,
    ZONE_SIDE,
    DashboardWidget,
)
from apps.core.dashboard.registry import register
from apps.core.dashboard.role_groups import (
    MEL_IMPLEMENTER_ROLES,
    MEL_ROLES,
    has_role,
)


# ── Shared gating / query helpers ────────────────────────────────────────


def _datapoint_model():
    from apps.mel.indicators.models import DataPoint

    return DataPoint


def _responsible_indicators(user):
    """Active indicators this user is the responsible officer on."""
    from apps.mel.indicators.models import Indicator

    if not getattr(user, "is_authenticated", False):
        return Indicator.objects.none()
    return Indicator.objects.filter(responsible=user, is_active=True)


def _is_officer(user) -> bool:
    # M&E Officers get their own dashboard; a superuser is treated as admin.
    return has_role(user, MEL_ROLES) or bool(
        getattr(user, "is_authenticated", False) and getattr(user, "is_superuser", False)
    )


def _is_implementer(user) -> bool:
    """True for a Program Coordinator/Implementer who should see this dashboard.

    Enabled by explicit role OR by the implicit "responsible on an active
    indicator" signal — but never for M&E Officers (excluded above).
    """
    if not getattr(user, "is_authenticated", False):
        return False
    if _is_officer(user):
        return False
    if has_role(user, MEL_IMPLEMENTER_ROLES):
        return True
    return _responsible_indicators(user).exists()


def _my_datapoints(user):
    DataPoint = _datapoint_model()
    return DataPoint.objects.filter(reported_by=user)


class _ImplementerWidget(DashboardWidget):
    """Base: enabled for the coordinator/implementer persona only."""

    @classmethod
    def is_enabled(cls, user) -> bool:
        return _is_implementer(user)


# ── KPI band ─────────────────────────────────────────────────────────────


class _ImplementerKPIBase(_ImplementerWidget):
    zone = ZONE_KPI
    template = "core/dashboard/widgets/kpi_card.html"
    zone_heading = "My progress reporting"
    zone_heading_url_name = "mel_indicators:validation_queue"
    zone_heading_action_label = "My submissions"


@register
class ImplementerMyIndicatorsKPI(_ImplementerKPIBase):
    key = "mel.impl.kpi.my_indicators"
    priority = 60

    def get_context(self, user) -> dict:
        n = _responsible_indicators(user).count()
        # data_entry 403s when the user is responsible on nothing, so only point
        # there when they actually have indicators to report on.
        href = reverse("mel_indicators:data_entry") if n else reverse(
            "mel_indicators:validation_queue"
        )
        return {
            "label": "Indicators assigned to me",
            "value": f"{n:,}",
            "hint": "Report implementation data" if n else "None assigned yet",
            "href": href,
        }


@register
class ImplementerPendingKPI(_ImplementerKPIBase):
    key = "mel.impl.kpi.pending"
    priority = 61

    def get_context(self, user) -> dict:
        DataPoint = _datapoint_model()
        n = _my_datapoints(user).filter(status=DataPoint.Status.PENDING).count()
        return {
            "label": "Awaiting validation",
            "value": f"{n:,}",
            "accent": "amber" if n else "primary",
            "hint": "Submitted, under M&E review" if n else "Nothing pending",
            "href": reverse("mel_indicators:validation_queue"),
        }


@register
class ImplementerClarificationKPI(_ImplementerKPIBase):
    key = "mel.impl.kpi.clarification"
    priority = 62

    def get_context(self, user) -> dict:
        DataPoint = _datapoint_model()
        n = (
            _my_datapoints(user)
            .filter(status=DataPoint.Status.NEEDS_CLARIFICATION)
            .count()
        )
        return {
            "label": "Needs your input",
            "value": f"{n:,}",
            "accent": "rose" if n else "primary",
            "hint": "Clarification requested" if n else "No follow-ups",
            "href": reverse("mel_indicators:validation_queue"),
        }


@register
class ImplementerVerifiedKPI(_ImplementerKPIBase):
    key = "mel.impl.kpi.verified"
    priority = 63

    def get_context(self, user) -> dict:
        DataPoint = _datapoint_model()
        n = _my_datapoints(user).filter(status=DataPoint.Status.VERIFIED).count()
        return {
            "label": "Verified",
            "value": f"{n:,}",
            "accent": "emerald" if n else "primary",
            "hint": "Accepted by the M&E team",
            "href": reverse("mel_indicators:validation_queue"),
        }


# ── Actions ──────────────────────────────────────────────────────────────


@register
class ImplementerQuickActions(_ImplementerWidget):
    key = "mel.impl.actions"
    zone = ZONE_ACTIONS
    priority = 50
    template = "core/dashboard/widgets/quick_actions.html"

    def get_context(self, user) -> dict:
        actions = []
        if _responsible_indicators(user).exists():
            actions.append({
                "label": "Submit implementation data",
                "href": reverse("mel_indicators:data_entry"),
                "primary": True,
                "icon": "M12 4v16m8-8H4",
            })
        actions.append({
            "label": "My submissions",
            "href": reverse("mel_indicators:validation_queue"),
            "icon": "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
        })
        return {"actions": actions}


# ── Primary: welcome banner + my indicators ──────────────────────────────


@register
class ImplementerWelcomeBanner(_ImplementerWidget):
    key = "mel.impl.banner"
    zone = ZONE_PRIMARY
    priority = 5
    template = "core/dashboard/widgets/banner_card.html"

    def get_context(self, user) -> dict:
        n = _responsible_indicators(user).count()
        if not n:
            return {
                "title": "No indicators assigned to you yet",
                "body": (
                    "Before you can submit implementation data, an M&E Officer "
                    "must assign you as the responsible officer on one or more "
                    "indicators. Once assigned, they'll appear here and you can "
                    "report progress each period."
                ),
                "accent": "amber",
            }
        return {
            "title": "Report your implementation progress",
            "body": (
                f"You're the responsible officer on {n} active "
                f"indicator{'s' if n != 1 else ''}. Submit implementation data "
                "for the current reporting period — the M&E team validates each "
                "submission before it updates the results framework."
            ),
            "cta_label": "Submit implementation data",
            "cta_href": reverse("mel_indicators:data_entry"),
        }


@register
class ImplementerMyIndicatorsWidget(_ImplementerWidget):
    key = "mel.impl.my_indicators"
    zone = ZONE_PRIMARY
    priority = 70
    template = "core/dashboard/widgets/list_card.html"

    def get_context(self, user) -> dict:
        DataPoint = _datapoint_model()
        # Open (unresolved) submissions per indicator, so the row badge tells the
        # implementer whether they've already reported this period.
        open_ids = set(
            _my_datapoints(user)
            .filter(
                status__in=(
                    DataPoint.Status.PENDING,
                    DataPoint.Status.NEEDS_CLARIFICATION,
                )
            )
            .values_list("indicator_id", flat=True)
        )
        qs = _responsible_indicators(user).order_by("code")[:6]
        items = []
        for ind in qs:
            unit = f" · {ind.unit}" if getattr(ind, "unit", "") else ""
            if ind.id in open_ids:
                badge, color = "Submitted", "amber"
            else:
                badge, color = "Report", "sky"
            items.append({
                "label": f"{ind.code}: {ind.name[:60]}",
                "sublabel": f"{ind.get_frequency_display()}{unit}"
                if hasattr(ind, "get_frequency_display")
                else unit.lstrip(" ·"),
                "badge": badge,
                "badge_color": color,
                "href": reverse("mel_indicators:data_entry"),
            })
        return {
            "title": "Indicators under my responsibility",
            "subtitle": "Activities you report implementation data for",
            "items": items,
            "empty_text": "No indicators are assigned to you yet.",
            "footer_href": reverse("mel_indicators:data_entry") if items else None,
            "footer_label": "Submit implementation data" if items else None,
        }


# ── Side: my recent submissions + their validation status ────────────────


@register
class ImplementerMySubmissionsWidget(_ImplementerWidget):
    key = "mel.impl.my_submissions"
    zone = ZONE_SIDE
    priority = 70
    template = "core/dashboard/widgets/list_card.html"

    def get_context(self, user) -> dict:
        DataPoint = _datapoint_model()
        qs = (
            _my_datapoints(user)
            .select_related("indicator")
            .order_by("-reported_at")[:6]
        )
        color_map = {
            DataPoint.Status.PENDING: "amber",
            DataPoint.Status.NEEDS_CLARIFICATION: "rose",
            DataPoint.Status.VERIFIED: "emerald",
            DataPoint.Status.REJECTED: "neutral",
        }
        items = []
        for dp in qs:
            code = dp.indicator.code if dp.indicator_id else "—"
            items.append({
                "label": f"{code}: {dp.indicator.name[:50]}"
                if dp.indicator_id
                else "Submission",
                "sublabel": f"{dp.period_label} · {dp.value}",
                "badge": dp.get_status_display(),
                "badge_color": color_map.get(dp.status, "neutral"),
                "href": reverse("mel_indicators:validation_queue"),
            })
        return {
            "title": "My recent submissions",
            "subtitle": "Implementation data you've reported",
            "items": items,
            "empty_text": "You haven't submitted any implementation data yet.",
            "footer_href": reverse("mel_indicators:validation_queue"),
            "footer_label": "View all my submissions",
        }
