"""SP14 — Lane filter drops acknowledged payer-rejected claims.

The Payer-Rejected Inbox lane must not include claims the operator
has already acknowledged. This is the working-surface UX: acknowledged
claims drop out so the operator only sees new rejections.
"""
from __future__ import annotations

from datetime import datetime, timezone

import pytest

from cyclone import db
from cyclone.db import Batch, Claim, ClaimState
from cyclone.inbox_lanes import compute_lanes


@pytest.fixture(autouse=True)
def _setup(tmp_path, monkeypatch):
    monkeypatch.setenv("CYCLONE_DB_URL", f"sqlite:///{tmp_path}/test.db")
    db._reset_for_tests()
    db.init_db()


def _seed(*, acked: bool = False) -> str:
    now = datetime.now(timezone.utc)
    cid = "C1"
    with db.SessionLocal()() as session:
        batch = Batch(
            id="b-1", kind="837p",
            input_filename="t.x12", parsed_at=now,
        )
        session.add(batch)
        session.flush()
        claim = Claim(
            id=cid, batch_id=batch.id, patient_control_number=cid,
            state=ClaimState.SUBMITTED, charge_amount=100,
            payer_rejected_at=now,
            payer_rejected_status_code="A7",
            payer_rejected_reason="invalid dx",
        )
        if acked:
            claim.payer_rejected_acknowledged_at = now
            claim.payer_rejected_acknowledged_actor = "operator"
        session.add(claim)
        session.commit()
    return cid


def test_unacknowledged_claim_appears_in_lane():
    _seed(acked=False)
    with db.SessionLocal()() as session:
        lanes = compute_lanes(session, dismissed_pairs=set())
    assert len(lanes.payer_rejected) == 1
    assert lanes.payer_rejected[0]["id"] == "C1"


def test_acknowledged_claim_drops_out_of_lane():
    _seed(acked=True)
    with db.SessionLocal()() as session:
        lanes = compute_lanes(session, dismissed_pairs=set())
    assert lanes.payer_rejected == []


def test_mix_of_acked_and_unacked():
    """Only the unacknowledged one shows up."""
    now = datetime.now(timezone.utc)
    with db.SessionLocal()() as session:
        batch = Batch(
            id="b-1", kind="837p",
            input_filename="t.x12", parsed_at=now,
        )
        session.add(batch)
        session.flush()
        for i, acked in enumerate([True, False, True, False]):
            claim = Claim(
                id=f"C{i}", batch_id=batch.id,
                patient_control_number=f"PCN-{i}",
                state=ClaimState.SUBMITTED, charge_amount=100,
                payer_rejected_at=now,
                payer_rejected_status_code="A7",
            )
            if acked:
                claim.payer_rejected_acknowledged_at = now
            session.add(claim)
        session.commit()

    with db.SessionLocal()() as session:
        lanes = compute_lanes(session, dismissed_pairs=set())
    ids = [r["id"] for r in lanes.payer_rejected]
    assert sorted(ids) == ["C1", "C3"]


def test_lane_row_carries_ack_fields_for_forward_compat():
    """The row payload still carries the ack fields (all null on the lane)
    so future views that want a 'Recently acknowledged' section don't need
    a schema change."""
    _seed(acked=False)
    with db.SessionLocal()() as session:
        lanes = compute_lanes(session, dismissed_pairs=set())
    row = lanes.payer_rejected[0]
    assert "payer_rejected_acknowledged_at" in row
    assert row["payer_rejected_acknowledged_at"] is None
    assert "payer_rejected_acknowledged_actor" in row
    assert row["payer_rejected_acknowledged_actor"] is None
