"""Semantic enum-value → badge-class maps for MEL.

Centralises the colour/strength mapping for the recurring inline status-pill
ladder pattern. Each map is keyed by the actual enum string used in MEL
models (severity, status, rag, peer_review_status) or the integer tier.

A map entry is ``(badge_class, strong, label)``:
  - ``badge_class`` — one of the .badge-* tokens defined in static/css/input.css
  - ``strong`` — True → adds the .badge--strong intensity modifier
  - ``label`` — the display text for the pill

Unknown values fall through to ``DEFAULT`` so the tag never blows up
in production on an enum value we haven't catalogued.
"""
from __future__ import annotations

# (badge_class, strong, label)
Entry = tuple[str, bool, str]

DEFAULT: Entry = ("badge-neutral", False, "—")


SEVERITY: dict[str, Entry] = {
    "critical": ("badge-rose", True, "Critical"),
    "high": ("badge-rose", False, "High"),
    "medium": ("badge-amber", False, "Medium"),
    "low": ("badge-neutral", False, "Low"),
}


# M&E SRS Table 66 — qualitative performance ratings are "On Track,
# Needs Attention, Critical". The RAG traffic-light maps onto those exact
# words so every pill speaks the framework's language.
RAG: dict[str, Entry] = {
    "green": ("badge-emerald", False, "On track"),
    "amber": ("badge-amber", False, "Needs attention"),
    "red": ("badge-rose", False, "Critical"),
    "unknown": ("badge-neutral", False, "Awaiting data"),
}


PEER_REVIEW: dict[str, Entry] = {
    "pending": ("badge-neutral", False, "Pending"),
    "in_review": ("badge-sky", False, "In review"),
    "approved": ("badge-emerald", False, "Approved"),
    "revisions_requested": ("badge-amber", False, "Revisions requested"),
}


TIER: dict[int, Entry] = {
    1: ("badge-amber", False, "Tier 1"),
    2: ("badge-amber", True, "Tier 2"),
    3: ("badge-rose", True, "Tier 3"),
}


# Status families — semantically grouped so adding a new status value picks
# the right colour family by intent, not by trial-and-error.
_STATUS_AFFIRMATIVE = ("badge-emerald", False)         # work landed
_STATUS_NEUTRAL = ("badge-neutral", False)             # not yet started
_STATUS_IN_FLIGHT = ("badge-sky", False)               # actively moving
_STATUS_WARNING = ("badge-amber", False)               # at risk
_STATUS_BLOCKED = ("badge-rose", False)                # failed / terminated

STATUS: dict[str, Entry] = {
    # Affirmative outcomes
    "published": (*_STATUS_AFFIRMATIVE, "Published"),
    "approved":  (*_STATUS_AFFIRMATIVE, "Approved"),
    "completed": (*_STATUS_AFFIRMATIVE, "Completed"),
    "done":      (*_STATUS_AFFIRMATIVE, "Done"),
    "actioned":  (*_STATUS_AFFIRMATIVE, "Actioned"),
    "closed":    (*_STATUS_AFFIRMATIVE, "Closed"),
    "active":    (*_STATUS_AFFIRMATIVE, "Active"),
    "verified":  (*_STATUS_AFFIRMATIVE, "Verified"),
    # Neutral / starting
    "incomplete":     (*_STATUS_WARNING, "Incomplete"),
    "draft":          (*_STATUS_NEUTRAL, "Draft"),
    "new":            (*_STATUS_NEUTRAL, "New"),
    "pending":        (*_STATUS_NEUTRAL, "Pending"),
    "non_responded":  (*_STATUS_NEUTRAL, "No response yet"),
    "archived":       (*_STATUS_NEUTRAL, "Archived"),
    "open":           (*_STATUS_NEUTRAL, "Open"),
    # In-flight
    "in_progress": (*_STATUS_IN_FLIGHT, "In progress"),
    "in_review":   (*_STATUS_IN_FLIGHT, "In review"),
    "triaged":     (*_STATUS_IN_FLIGHT, "Triaged"),
    # At risk
    "delayed":             (*_STATUS_WARNING, "Delayed"),
    "stalled":             (*_STATUS_WARNING, "Stalled"),
    "revisions_requested": (*_STATUS_WARNING, "Revisions requested"),
    "needs_clarification": (*_STATUS_WARNING, "Clarification requested"),
    "flagged":             (*_STATUS_WARNING, "Flagged"),
    # Failed / terminated
    "overdue":   (*_STATUS_BLOCKED, "Overdue"),
    "failed":    (*_STATUS_BLOCKED, "Failed"),
    "rejected":  (*_STATUS_BLOCKED, "Rejected"),
    "cancelled": (*_STATUS_BLOCKED, "Cancelled"),
    "exited":    (*_STATUS_BLOCKED, "Exited"),
}


# Feedback-channel intake types — one pill per channel.type enum value
CHANNEL_TYPE: dict[str, Entry] = {
    "report_review": ("badge-sky", False, "Report review"),
    "beneficiary":   ("badge-emerald", False, "Beneficiary"),
    "industry":      ("badge-amber", False, "Industry"),
    "alumni":        ("badge-violet", False, "Alumni"),
    "moodle":        ("badge-rose", False, "Moodle"),
}


# Results-hierarchy row level — impact/intermediate outcome/output/activity/input
# (the Strategic Objective is the framework container, not a row level).
LEVEL: dict[str, Entry] = {
    "impact":   ("badge-violet", False, "Impact"),
    "outcome":  ("badge-sky", False, "Intermediate Outcome"),
    "output":   ("badge-emerald", False, "Output"),
    "activity": ("badge-amber", False, "Activity"),
    "input":    ("badge-neutral", False, "Input"),
}


MAPS: dict[str, dict] = {
    "severity": SEVERITY,
    "status": STATUS,
    "rag": RAG,
    "peer_review": PEER_REVIEW,
    "tier": TIER,
    "channel_type": CHANNEL_TYPE,
    "level": LEVEL,
}


def resolve(kind: str, value) -> Entry:
    """Return the (badge_class, strong, label) entry for a given kind+value.

    Unknown ``kind`` or unknown ``value`` falls through to :data:`DEFAULT`.
    ``value`` is normalised via ``str().lower().strip()`` for string maps
    (severity/status/rag/peer_review) so 'Critical' and 'critical' both
    resolve. Tier accepts int.
    """
    table = MAPS.get(kind)
    if table is None or value is None:
        return DEFAULT
    if kind == "tier":
        try:
            return table.get(int(value), DEFAULT)
        except (TypeError, ValueError):
            return DEFAULT
    key = str(value).strip().lower()
    return table.get(key, DEFAULT)
