"""IndicatorDetailView data-point pagination + sparkline stability.

The data-point table was hard-capped at ``[:100]`` and also fed the sparkline.
It now paginates (``?dp_page=``) while the sparkline reads its own recent slice,
so paging the table must not blank or change the sparkline.
"""
from __future__ import annotations

from datetime import date
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 (
    Indicator,
    IndicatorFrequency,
    IndicatorVariance,
    LogFrame,
    LogFrameLevel,
    LogFrameRow,
)
from apps.mel.indicators.services import record_data_point

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


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


def _indicator_with_points(n):
    lf = LogFrame.objects.create(name="LF-P", slug="lf-pager")
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="I")
    outcome = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTCOME, title="O", parent=impact
    )
    output = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTPUT, title="P", parent=outcome
    )
    ind = Indicator.objects.create(
        logframe_row=output,
        code="pager-ind",
        name="I",
        data_source="m",
        unit="count",
        calculation_method="Count.",
        frequency=IndicatorFrequency.MONTHLY,
    )
    for i in range(n):
        record_data_point(
            indicator=ind,
            value=Decimal(i + 1),
            period_label=f"2026-{(i % 12) + 1:02d}",
            reported_at=date(2026, 1, 1),
            source_module="m",
            source_object_id=str(i),
            auto_verify=True,
        )
    return ind


def test_data_points_paginate_at_25(client, officer):
    ind = _indicator_with_points(30)
    client.force_login(officer)
    url = reverse("mel_indicators:indicator_detail", kwargs={"code": ind.code})

    resp = client.get(url, HTTP_HOST="localhost")
    assert resp.status_code == 200
    page = resp.context["data_points"]
    assert page.paginator.count == 30
    assert page.paginator.num_pages == 2
    assert len(page.object_list) == 25

    resp2 = client.get(url, {"dp_page": 2}, HTTP_HOST="localhost")
    assert len(resp2.context["data_points"].object_list) == 5


def test_sparkline_is_stable_across_data_point_pages(client, officer):
    ind = _indicator_with_points(30)
    client.force_login(officer)
    url = reverse("mel_indicators:indicator_detail", kwargs={"code": ind.code})

    p1 = client.get(url, HTTP_HOST="localhost")
    p2 = client.get(url, {"dp_page": 2}, HTTP_HOST="localhost")

    # Sparkline reads its own recent slice — present and identical on both pages,
    # not derived from the (now paginated) table rows.
    assert p1.context["sparkline"]["has_data"] is True
    assert p2.context["sparkline"]["has_data"] is True
    assert p1.context["sparkline"] == p2.context["sparkline"]


# ---------------------------------------------------------------------------
# P2 — IndicatorVarianceView: paginate the table, keep band stats whole-set
# ---------------------------------------------------------------------------

def _indicator():
    lf = LogFrame.objects.create(name="LF-V", slug="lf-var-pager")
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="I")
    outcome = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTCOME, title="O", parent=impact
    )
    output = LogFrameRow.objects.create(
        logframe=lf, level=LogFrameLevel.OUTPUT, title="P", parent=outcome
    )
    return Indicator.objects.create(
        logframe_row=output,
        code="var-pager-ind",
        name="I",
        data_source="m",
        unit="count",
        calculation_method="Count.",
        frequency=IndicatorFrequency.MONTHLY,
    )


def test_variance_table_paginates_but_band_stats_span_all_rows(client, officer):
    ind = _indicator()
    # 30 snapshots, all critical (-60%): band stats must count all 30 even though
    # only 25 render on page 1.
    IndicatorVariance.objects.bulk_create(
        IndicatorVariance(
            indicator=ind,
            period_label=f"2026-{i:02d}",
            variance_pct=Decimal("-60.0"),
        )
        for i in range(30)
    )
    client.force_login(officer)
    url = reverse("mel_indicators:indicator_variance", kwargs={"code": ind.code})

    resp = client.get(url, HTTP_HOST="localhost")
    assert resp.status_code == 200
    page = resp.context["variances"]
    assert page.paginator.count == 30
    assert len(page.object_list) == 25
    # Stats aggregate the whole set, not the page.
    assert resp.context["variance_stats"]["critical"] == 30

    resp2 = client.get(url, {"var_page": 2}, HTTP_HOST="localhost")
    assert len(resp2.context["variances"].object_list) == 5
    assert resp2.context["variance_stats"]["critical"] == 30


# ---------------------------------------------------------------------------
# P2 — ConsolidatedAuditLogView: real paginator over the merged window.
# Admin-only view → use RequestFactory + as_view to bypass the MFA middleware
# (mirrors apps/mel/indicators/tests/test_audit_log.py), asserting on the
# rendered pager since render() responses carry no .context.
# ---------------------------------------------------------------------------

def _seed_indicator_history(n):
    ind = _indicator()
    for i in range(n):
        Indicator.objects.create(
            logframe_row=ind.logframe_row,
            code=f"audit-pager-{i}",
            name=f"X {i}",
            data_source="m",
            unit="count",
            calculation_method="Count.",
            frequency=IndicatorFrequency.MONTHLY,
        )
    admin = User.objects.create_user(
        email="audit-pager@example.com", password="x",
        is_staff=True, is_superuser=True, role=UserRole.SYSTEM_ADMIN,
    )
    return admin


def test_audit_log_paginates_merged_history():
    from django.test import RequestFactory

    from apps.mel.indicators.views import ConsolidatedAuditLogView

    admin = _seed_indicator_history(60)
    rf = RequestFactory()
    url = reverse("mel_indicators:audit_log")

    # Page 1, filtered to the Indicator source: a "next" link to page 2 appears.
    req = rf.get(url + "?model=Indicator")
    req.user = admin
    resp = ConsolidatedAuditLogView.as_view()(req)
    assert resp.status_code == 200
    html = resp.content.decode()
    assert "page=2" in html  # next-page link in the pager
    assert "Page" in html and "of" in html

    # Page 2 renders with a "previous" link back to page 1.
    req2 = rf.get(url + "?model=Indicator&page=2")
    req2.user = admin
    resp2 = ConsolidatedAuditLogView.as_view()(req2)
    assert resp2.status_code == 200
    assert "page=1" in resp2.content.decode()
