"""SP32 Task 6: end-to-end smoke tests for the ``backfill-rendering-npi`` CLI.

The CLI re-parses on-disk 837p + 835 files and backfills the new typed
``rendering_provider_npi`` columns on existing Claim / Remittance rows
that were ingested before the T4 writers took effect. Idempotent: rows
that already have a non-NULL rendering NPI are left untouched.

Test strategy mirrors ``test_cli_backup.py``: in-process Click CliRunner
invocation against a fresh per-test DB (autouse ``_auto_init_db``
fixture), pre-seeded with Claim/Remittance rows whose
``rendering_provider_npi`` is NULL, then assert the CLI populated them.
"""

from __future__ import annotations

from datetime import datetime, timezone
from decimal import Decimal

import pytest
from click.testing import CliRunner

from cyclone import db
from cyclone.cli import main

BACKEND_DIR = "backend"
_REPO_ROOT = "."


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


@pytest.fixture
def seed_837p_claim_without_renderer():
    """Insert a Claim row whose ``rendering_provider_npi`` is NULL.

    The id (``t991102984o1c1d``) matches the first claim in
    ``co_medicaid_837p_with_renderer.txt`` — the fixture that does
    contain a NM1*82 rendering provider (NPI ``1234567893``) attached
    to that claim. Backfill should populate the column from the
    re-parsed file.
    """
    from cyclone.db import Batch, Claim, ClaimState
    with db.SessionLocal()() as s:
        s.add(Batch(
            id="seed-837p-batch",
            kind="837p",
            input_filename="seed.x12",
            parsed_at=datetime.now(timezone.utc),
        ))
        s.add(Claim(
            id="t991102984o1c1d",
            batch_id="seed-837p-batch",
            patient_control_number="t991102984o1c1d",
            charge_amount=Decimal("85.40"),
            state=ClaimState.SUBMITTED,
            rendering_provider_npi=None,  # ← the column under test
            provider_npi="1881068062",
        ))
        s.commit()


@pytest.fixture
def seed_835_remit_without_service_provider(tmp_path):
    """Insert a Remittance whose ``rendering_provider_npi`` is NULL.

    Writes a minimal 835 fixture to ``tmp_path`` containing an
    NM1*1P service provider (NPI ``2222222222``) attached to the
    only CLP segment (claim control number ``CLM001``). Returns
    the path to the written file.
    """
    from cyclone.db import Batch, Remittance

    fixture = tmp_path / "minimal_835_with_service_provider.txt"
    fixture.write_text(
        "ISA*00*          *00*          *ZZ*RECEIVERID     *ZZ*SENDERID       "
        "*250101*1200*^*00501*000000001*0*P*:~"
        "GS*HP*RECEIVER*SENDER*20250101*1200*1*X*005010X221A1~"
        "ST*835*0001~"
        "BPR*I*85.40*C*NON*****01*021000021*DA*123456*1511111"
        "**01*031302955*DA*9876543~"
        "TRN*1*1511111*1511111~"
        "DTM*405*20250101~"
        "N1*PR*COLORADO MEDICAID*XV*CO MEDICAID~"
        "N3*PO BOX 1100*~"
        "N4*DENVER*CO*80203~"
        "REF*2U*12345~"
        "N1*PE*ACME CLINIC*XX*1111111111~"
        "LX*1~"
        "CLP*CLM001*1*85.40*85.40*0.00*MC*CLM001*11*1~"
        "CAS*PR*1*0.00~"
        "NM1*1P*2*RENDERING PROVIDER*****XX*2222222222~"
        "SVC*HC:99213*85.40*85.40**1~"
        "DTM*472*20250101~"
        "SE*18*0001~"
        "GE*1*1~"
        "IEA*1*000000001~"
    )

    with db.SessionLocal()() as s:
        s.add(Batch(
            id="seed-835-batch",
            kind="835",
            input_filename=fixture.name,
            parsed_at=datetime.now(timezone.utc),
        ))
        s.add(Remittance(
            id="CLM001",
            batch_id="seed-835-batch",
            payer_claim_control_number="CLM001",
            claim_id=None,
            status_code="1",
            status_label="Primary payer forward",
            total_charge=Decimal("85.40"),
            total_paid=Decimal("85.40"),
            patient_responsibility=Decimal("0"),
            adjustment_amount=Decimal("0"),
            received_at=datetime.now(timezone.utc),
            is_reversal=False,
            rendering_provider_npi=None,  # ← the column under test
        ))
        s.commit()

    return fixture


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _run(args: list[str]) -> object:
    """Invoke the CLI in-process via CliRunner.

    CliRunner auto-captures stdout/stderr; ``catch_exceptions=False``
    so the test fails loudly on any unexpected raise instead of a
    swallowed traceback.
    """
    return CliRunner().invoke(main, args, catch_exceptions=False)


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------


def test_backfill_populates_837p_rendering_npi(seed_837p_claim_without_renderer):
    """Re-parse the 837p fixture → Claim.rendering_provider_npi populated."""
    fixture_path = "tests/fixtures/co_medicaid_837p_with_renderer.txt"

    # Sanity: column starts NULL.
    with db.SessionLocal()() as s:
        from cyclone.db import Claim
        row = s.get(Claim, "t991102984o1c1d")
        assert row is not None
        assert row.rendering_provider_npi is None

    result = _run(["backfill-rendering-npi", "--file", fixture_path, "--type", "837p"])
    assert result.exit_code == 0, result.output

    with db.SessionLocal()() as s:
        from cyclone.db import Claim
        row = s.get(Claim, "t991102984o1c1d")
        assert row is not None
        # First claim in the fixture carries NM1*82 NPI ``1234567893``.
        assert row.rendering_provider_npi == "1234567893"
    # CLI prints the summary line with the populated counts.
    assert "claims_updated=" in result.output
    assert "remits_updated=" in result.output


def test_backfill_populates_835_rendering_npi(seed_835_remit_without_service_provider):
    """Re-parse an 835 with NM1*1P → Remittance.rendering_provider_npi populated."""
    fixture_path = str(seed_835_remit_without_service_provider)

    # Sanity: column starts NULL.
    with db.SessionLocal()() as s:
        from cyclone.db import Remittance
        row = s.get(Remittance, "CLM001")
        assert row is not None
        assert row.rendering_provider_npi is None

    result = _run(["backfill-rendering-npi", "--file", fixture_path, "--type", "835"])
    assert result.exit_code == 0, result.output

    with db.SessionLocal()() as s:
        from cyclone.db import Remittance
        row = s.get(Remittance, "CLM001")
        assert row is not None
        # Inline fixture's NM1*1P NM109 is ``2222222222``.
        assert row.rendering_provider_npi == "2222222222"
    assert "remits_updated=" in result.output


def test_backfill_is_idempotent(seed_837p_claim_without_renderer):
    """Second run is a no-op — already-populated columns stay."""
    fixture_path = "tests/fixtures/co_medicaid_837p_with_renderer.txt"

    # First run: populates the column.
    first = _run(["backfill-rendering-npi", "--file", fixture_path, "--type", "837p"])
    assert first.exit_code == 0, first.output

    # Second run: still exits 0; column is unchanged; nothing breaks.
    second = _run(["backfill-rendering-npi", "--file", fixture_path, "--type", "837p"])
    assert second.exit_code == 0, second.output

    with db.SessionLocal()() as s:
        from cyclone.db import Claim
        row = s.get(Claim, "t991102984o1c1d")
        assert row.rendering_provider_npi == "1234567893"


def test_backfill_help_lists_subcommand():
    """Regression guard: the subcommand is wired into ``main``."""
    result = _run(["--help"])
    assert result.exit_code == 0
    assert "backfill-rendering-npi" in result.output


def test_backfill_with_no_files_is_noop():
    """Running with no --file and no --input-dir is a clean no-op (exit 0)."""
    result = _run(["backfill-rendering-npi"])
    assert result.exit_code == 0, result.output
    # Summary line still printed (zero counts).
    assert "claims_updated=0" in result.output
    assert "remits_updated=0" in result.output
