"""M&EL dashboard redesign — Strategic-Objective-centric layout.

After the results-framework refactor the dashboard leads with a per-Strategic-
Objective scorecard grid (reverse aggregation Output → Outcome → Impact), a thin
portfolio strip, a data-completeness callout, and a consolidated 'what needs
action' block. This locks in that IA so a future edit can't silently regress it.

Do NOT run under a parallel pytest — the test_iilmp DB collides.
"""
from __future__ import annotations

from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse

from apps.core.permissions.roles import UserRole
from apps.mel.indicators.models import (
    DataPoint,
    Indicator,
    IndicatorFrequency,
    IndicatorTarget,
    LogFrame,
    LogFrameLevel,
    LogFrameRow,
)

User = get_user_model()
pytestmark = pytest.mark.django_db


@pytest.fixture
def officer():
    return User.objects.create_user(
        email="dash-officer@example.com", password="x", role=UserRole.MEL_OFFICER,
    )


@pytest.fixture
def objective_with_data():
    """A Strategic Objective (LogFrame) with a full chain + an Output indicator
    that has a target and a measurement, so the scorecard has a real rollup."""
    lf = LogFrame.objects.create(
        name="SO — graduate employability", slug="so-dash", code="SO-DASH",
        planning_period="2024–2028",
    )
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="Impact")
    outcome = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTCOME, title="Outcome", parent=impact,
    )
    output = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTPUT, title="Output", parent=outcome,
    )
    ind = Indicator.objects.create(
        logframe_row=output, code="dash-out", name="Graduates placed",
        unit="people", calculation_method="count", data_source="manual",
        frequency=IndicatorFrequency.QUARTERLY,
    )
    IndicatorTarget.objects.create(
        indicator=ind, period_label="2026Q2",
        period_start=date(2026, 4, 1), period_end=date(2026, 6, 30),
        baseline_value=Decimal("0"), target_value=Decimal("100"),
    )
    # Only VERIFIED datapoints feed the rollup (sum_period_value).
    DataPoint.objects.create(
        indicator=ind, value=Decimal("40"), period_label="2026Q2",
        reported_at=date.today() - timedelta(days=10),
        status=DataPoint.Status.VERIFIED,
    )
    return lf


def test_dashboard_leads_with_strategic_objective_scorecards(client, officer, objective_with_data):
    client.force_login(officer)
    # Pin the reporting period to the one our measurement covers, so the rollup
    # is deterministic regardless of the wall-clock "current" period.
    resp = client.get(reverse("mel_tracking:tracking_dashboard"), {"period": "2026Q2"})
    assert resp.status_code == 200
    ctx = resp.context

    # The SO scorecard dataset is populated with a card per active objective.
    cards = ctx["strategic_objectives"]
    assert ctx["strategic_objectives_count"] == len(cards)
    card = next(c for c in cards if c["logframe"].pk == objective_with_data.pk)
    assert card["indicator_count"] == 1
    # Bands are ordered top-down: Impact, Outcomes, Outputs.
    assert [b["title"] for b in card["bands"]] == ["Impact", "Outcomes", "Outputs"]
    # The Output band carries the measured attainment (40 of 100 = 40%).
    output_band = next(b for b in card["bands"] if b["key"] == "output")
    assert output_band["count"] == 1
    assert output_band["attainment"] == 40.0
    assert output_band["rag"] == "red"  # below 60%


def test_dashboard_renders_new_information_architecture(client, officer, objective_with_data):
    client.force_login(officer)
    body = client.get(reverse("mel_tracking:tracking_dashboard")).content.decode()

    # New structure present.
    assert "Strategic Objectives</h2>" in body
    assert "Data validation" in body                 # module rail (4 M&E hubs)
    assert "What needs action" in body               # consolidated actions
    assert "More — cross-module reach" in body       # demoted tail
    assert "SO — graduate employability" in body     # a scorecard rendered

    # Old kitchen-sink headings are gone.
    assert "Indicator health" not in body
    assert "Results-chain performance" not in body
    assert "Top programmes by health" not in body
