"""G10 — Bulk CSV import for DataPoints.

Verifies dry-run / commit / idempotent-replay / G9-validation-honouring
behaviour of :func:`import_data_points_csv`.
"""
from __future__ import annotations

import pytest

from apps.mel.indicators.models import (
    DataPoint,
    Indicator,
    IndicatorFrequency,
    LogFrame,
    LogFrameLevel,
    LogFrameRow,
    ValidationRule,
)
from apps.mel.indicators.services import import_data_points_csv


pytestmark = pytest.mark.django_db


def _build_indicator(code: str):
    lf = LogFrame.objects.create(name=f"LF {code}", slug=f"lf-{code}")
    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=code,
        name=code.upper(),
        unit="%",
        calculation_method="mean",
        data_source="manual",
        frequency=IndicatorFrequency.QUARTERLY,
    )


_HEADER = "indicator_code,period_label,value,evidence_url,reported_at,notes\n"


def test_import_creates_data_points_on_commit():
    _build_indicator("g10-a")
    csv = _HEADER + "g10-a,2026Q1,42,,,\n" + "g10-a,2026Q2,55,,,\n"
    result = import_data_points_csv(
        csv_text=csv, csv_bytes=csv.encode("utf-8"), user=None, dry_run=False,
    )
    assert len(result["successes"]) == 2
    assert result["errors"] == []
    assert DataPoint.objects.count() == 2


def test_import_dry_run_does_not_create():
    _build_indicator("g10-dry")
    csv = _HEADER + "g10-dry,2026Q1,42,,,\n"
    result = import_data_points_csv(
        csv_text=csv, csv_bytes=csv.encode("utf-8"), user=None, dry_run=True,
    )
    assert len(result["successes"]) == 1
    assert DataPoint.objects.count() == 0


def test_import_idempotent_on_replay():
    _build_indicator("g10-replay")
    csv = _HEADER + "g10-replay,2026Q1,42,,,\n" + "g10-replay,2026Q2,55,,,\n"
    body = csv.encode("utf-8")
    import_data_points_csv(csv_text=csv, csv_bytes=body, user=None, dry_run=False)
    assert DataPoint.objects.count() == 2
    # Re-upload the exact same file — same batch_id → same source_object_ids →
    # no new rows.
    second = import_data_points_csv(
        csv_text=csv, csv_bytes=body, user=None, dry_run=False,
    )
    assert DataPoint.objects.count() == 2
    # Every row reports created=False on replay.
    assert all(not ok["created"] for ok in second["successes"])


def test_import_reports_invalid_indicator_code_as_row_error():
    _build_indicator("g10-known")
    csv = _HEADER + "unknown-code,2026Q1,1,,,\n" + "g10-known,2026Q1,2,,,\n"
    result = import_data_points_csv(
        csv_text=csv, csv_bytes=csv.encode("utf-8"), user=None, dry_run=False,
    )
    assert len(result["successes"]) == 1
    assert len(result["errors"]) == 1
    assert result["errors"][0]["indicator_code"] == "unknown-code"
    assert "not found" in result["errors"][0]["error"]


def test_import_respects_g9_validation_rules():
    ind = _build_indicator("g10-rule")
    ValidationRule.objects.create(
        indicator=ind,
        rule_type=ValidationRule.RuleType.RANGE,
        params={"min": 0, "max": 100},
        message="Percentage must be 0–100",
    )
    csv = _HEADER + "g10-rule,2026Q1,150,,,\n"
    result = import_data_points_csv(
        csv_text=csv, csv_bytes=csv.encode("utf-8"), user=None, dry_run=False,
    )
    assert result["successes"] == []
    assert len(result["errors"]) == 1
    assert "Percentage must be 0–100" in result["errors"][0]["error"]
    assert DataPoint.objects.count() == 0


def test_import_missing_required_column_returns_top_level_error():
    csv = "indicator_code,value\nabc,1\n"
    result = import_data_points_csv(
        csv_text=csv, csv_bytes=csv.encode("utf-8"), user=None, dry_run=True,
    )
    assert result["successes"] == []
    assert len(result["errors"]) == 1
    assert "period_label" in result["errors"][0]["error"]
