"""FRREP-AR012 — daily M&EL indicator push, delivered in-process.

Covers ``apps.repository.integration.mel_feed.deliver`` for
``event_type="daily_indicators"``: previously this only ever POSTed to
``REPOSITORY_MEL_PUSH_URL`` (blank in every env file, so it silently
no-op'd). It now writes directly into ``apps.mel.indicators.DataPoint`` rows
in-process when a matching ``Indicator`` is wired up.
"""

from __future__ import annotations

import pytest

from apps.repository.documents.models import IntegrationOutbox
from apps.repository.integration import mel_feed


def _make_outbox(payload: dict) -> IntegrationOutbox:
    return IntegrationOutbox.objects.create(
        target=IntegrationOutbox.Target.MEL,
        event_type="daily_indicators",
        payload=payload,
    )


def _make_indicator(auto_event_type: str):
    from apps.mel.indicators.models import (
        Indicator,
        IndicatorFrequency,
        LogFrame,
        LogFrameLevel,
        LogFrameRow,
    )

    lf = LogFrame.objects.create(name=f"LF-{auto_event_type}", slug=f"lf-{auto_event_type}")
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="Impact")
    return Indicator.objects.create(
        logframe_row=impact,
        code=f"ind-{auto_event_type}",
        name=f"Indicator for {auto_event_type}",
        data_source="repository",
        frequency=IndicatorFrequency.DAILY,
        source_module="repository",
        auto_event_type=auto_event_type,
    )


@pytest.mark.django_db
def test_deliver_writes_data_point_when_indicator_wired():
    from apps.mel.indicators.models import DataPoint

    indicator = _make_indicator("repository_total_documents")
    row = _make_outbox({"report_date": "2026-06-01", "total_documents": 42})

    mel_feed.deliver(row)

    dp = DataPoint.objects.get(indicator=indicator, source_module="repository")
    assert dp.value == 42
    assert dp.source_event == "daily_indicators"
    assert dp.status == DataPoint.Status.VERIFIED


@pytest.mark.django_db
def test_deliver_is_idempotent_on_replay():
    from apps.mel.indicators.models import DataPoint

    _make_indicator("repository_total_documents")
    row = _make_outbox({"report_date": "2026-06-02", "total_documents": 10})

    mel_feed.deliver(row)
    mel_feed.deliver(row)

    assert DataPoint.objects.filter(source_module="repository", period_label="2026-06-02").count() == 1


@pytest.mark.django_db
def test_deliver_skips_gracefully_when_no_indicator_wired():
    """No Indicator configured for source_module='repository' — must not raise."""
    from apps.mel.indicators.models import DataPoint

    row = _make_outbox({"report_date": "2026-06-03", "total_documents": 5})
    mel_feed.deliver(row)  # must not raise

    assert not DataPoint.objects.filter(source_module="repository").exists()


@pytest.mark.django_db
def test_deliver_writes_audit_receipt():
    """The audit write goes through ``log_audit`` -> ``transaction.on_commit``
    -> a Celery task, which is unreliable to assert on from a plain function
    call in tests (no HTTP request/response cycle to anchor the commit).
    Assert on the call contract instead: `audit_repository` is invoked with a
    success receipt reflecting the matched/written counts."""
    from unittest.mock import patch

    _make_indicator("repository_open_access_rate")
    row = _make_outbox({"report_date": "2026-06-04", "open_access_rate": 87.5})

    with patch("apps.repository.documents.audit_helper.audit_repository") as mock_audit:
        mel_feed.deliver(row)

    mock_audit.assert_called_once()
    kwargs = mock_audit.call_args.kwargs
    assert kwargs["action"] == "MEL_DAILY_INDICATORS_PUSHED"
    assert kwargs["target_model"] == "IntegrationOutbox"
    assert kwargs["changes"]["matched_indicators"] == 1
    assert kwargs["changes"]["data_points_written"] == 1


@pytest.mark.django_db
def test_deliver_other_event_type_falls_back_to_log_only(settings):
    """document_published (and other non-daily_indicators events) keep the
    old HTTP-or-log behaviour — must not touch M&EL DataPoints."""
    from apps.mel.indicators.models import DataPoint

    settings.REPOSITORY_MEL_PUSH_URL = ""
    row = IntegrationOutbox.objects.create(
        target=IntegrationOutbox.Target.MEL,
        event_type="document_published",
        payload={"document_id": 1},
    )
    mel_feed.deliver(row)  # must not raise
    assert not DataPoint.objects.filter(source_module="repository").exists()
