"""SP7 — integration test: reconcile.run() persists LineReconciliation rows.

Spec §4.4.

Architecture note: 837 service lines are stored inside
``Claim.raw_json["service_lines"]`` keyed by ``line_number`` (1-based).
The ``LineReconciliation`` table therefore stores
``claim_service_line_number`` (int), not a FK to a separate service_lines
table.
"""
from datetime import date, datetime, timezone
from decimal import Decimal
import json
import uuid

from sqlalchemy import select

from cyclone.db import (
    Batch,
    Claim,
    LineReconciliation,
    SessionLocal,
)
from cyclone.reconcile import run
from cyclone.store import _persist_835_remit, _remittance_835_row
from cyclone.parsers.models_835 import ClaimPayment, ServicePayment


def _setup_db() -> tuple:
    """Build a minimal 837 claim + 835 remit that share PCN. Returns (claim_id, batch_id)."""
    bid = str(uuid.uuid4())
    claim_id = "CLM-T1"
    service_lines_json = [
        {
            "line_number": 1,
            "procedure": {"qualifier": "HC", "code": "99213", "modifiers": []},
            "charge": "100.00",
            "unit_type": "UN",
            "units": "1",
            "place_of_service": "11",
            "service_date": "2026-06-01",
            "provider_reference": None,
        },
        {
            "line_number": 2,
            "procedure": {"qualifier": "HC", "code": "99214", "modifiers": []},
            "charge": "100.00",
            "unit_type": "UN",
            "units": "1",
            "place_of_service": "11",
            "service_date": "2026-06-01",
            "provider_reference": None,
        },
    ]

    with SessionLocal()() as s:
        # 1. Batch
        s.add(Batch(
            id=bid, kind="835", input_filename="x.835",
            parsed_at=datetime.now(timezone.utc),
            totals_json={"total_claims": 1, "total_paid": "150"},
            validation_json={"passed": True, "warnings": [], "errors": []},
            raw_result_json={"_": "stub"},
        ))
        # 2. Claim with two service lines (in raw_json)
        s.add(Claim(
            id=claim_id,
            patient_control_number="PCN-1",
            charge_amount=Decimal("200.00"),
            provider_npi="1234567890",
            payer_id="SKCO0",
            service_date_from=date(2026, 6, 1),
            service_date_to=date(2026, 6, 1),
            state="submitted",
            batch_id=bid,
            raw_json={"service_lines": service_lines_json},
        ))
        # 3. Remit with two SVC composites — line 1 matches 99213, line 2
        #    is 90837 (no claim match).
        cp = ClaimPayment(
            payer_claim_control_number="PCN-1",
            status_code="1",
            total_charge=Decimal("200.00"),
            total_paid=Decimal("150.00"),
            service_payments=[
                ServicePayment(
                    line_number=1, procedure_qualifier="HC",
                    procedure_code="99213",
                    charge=Decimal("100.00"),
                    payment=Decimal("80.00"),
                    units=Decimal("1"),
                    service_date=date(2026, 6, 1),
                ),
                ServicePayment(
                    line_number=2, procedure_qualifier="HC",
                    procedure_code="90837",
                    charge=Decimal("100.00"),
                    payment=Decimal("70.00"),
                    units=Decimal("1"),
                    service_date=date(2026, 6, 1),
                ),
            ],
        )
        remit = _remittance_835_row(cp, bid)
        s.add(remit)
        s.flush()
        _persist_835_remit(s, cp, remit.id)
        s.commit()

    return claim_id, bid


def test_run_persists_line_reconciliation_rows():
    claim_id, bid = _setup_db()
    with SessionLocal()() as s:
        result = run(s, bid)
        s.commit()
        assert result.matched == 1

        lrs = list(
            s.execute(
                select(LineReconciliation).where(LineReconciliation.claim_id == claim_id)
            ).scalars().all()
        )
        # Expect 3 rows: 99213 matched, 99214 unmatched_837_only, 90837 unmatched_835_only
        assert len(lrs) == 3
        by_status = {lr.status for lr in lrs}
        assert by_status == {"matched", "unmatched_837_only", "unmatched_835_only"}
