"""SP37 Task 3: batch_envelope_index populates from BOTH columns.

The dict returned by ``batch_envelope_index`` should resolve lookups
by EITHER ``Batch.raw_result_json.envelope.control_number`` (ISA13,
preserved) OR ``Batch.transaction_set_control_number`` (ST02, new in
SP37 Task 2). One dict, both keys — a single ``.get(set_control_number)``
call hits whichever matches, so the D10 Pass 1 join in
:func:`cyclone.claim_acks.lookup_claims_for_ack_set_response` resolves
999 AK201 (which echoes the source 837's ST02) back to the right batch
even when ST02 != ISA13.
"""
from __future__ import annotations

from datetime import datetime, timezone

import pytest

from cyclone import db as db_mod
from cyclone.db import Batch
from cyclone.store.claim_acks import batch_envelope_index


@pytest.fixture(autouse=True)
def _db(tmp_path, monkeypatch):
    """Per-test DB; conftest's autouse already wires one too, but we
    pin the URL again so this module is self-contained if anyone ever
    lifts it out of the conftest tree."""
    monkeypatch.setenv("CYCLONE_DB_URL", f"sqlite:///{tmp_path}/test.db")
    db_mod._reset_for_tests()
    db_mod.init_db()
    yield


def _make_batch(
    s,
    *,
    id: str,
    icn: str,
    stcn: str | None = None,
    raw_json: dict | None = None,
) -> Batch:
    """Insert one Batch row whose envelope + ST02 mirror what
    ``store.write.add_record`` writes for an 837P batch."""
    row = Batch(
        id=id,
        kind="837p",
        input_filename=id + ".x12",
        parsed_at=datetime.now(timezone.utc),
        raw_result_json=raw_json or {"envelope": {"control_number": icn}},
        transaction_set_control_number=stcn,
    )
    s.add(row)
    s.commit()
    s.refresh(row)
    return row


def test_index_resolves_by_envelope_control_number():
    """Pre-SP37 path: ISA13 (envelope.control_number) still resolves."""
    with db_mod.SessionLocal()() as s:
        _make_batch(s, id="b1", icn="ISA000001")
    idx = batch_envelope_index()
    assert idx.get("ISA000001") == "b1"


def test_index_resolves_by_transaction_set_control_number():
    """SP37 path: ST02 (transaction_set_control_number) resolves too.

    The whole point of Task 3 — Gainwell batches have ST02 != ISA13,
    so 999 AK201 echoes ST02 and must hit this branch.
    """
    with db_mod.SessionLocal()() as s:
        _make_batch(
            s, id="b2", icn="ISA000002", stcn="ST000002",
            raw_json={"envelope": {"control_number": "ISA000002"}},
        )
    idx = batch_envelope_index()
    assert idx.get("ST000002") == "b2"
    # Backward compat: ISA still resolves.
    assert idx.get("ISA000002") == "b2"


def test_index_handles_row_with_no_transaction_set_control_number():
    """Pre-migration rows (stcn NULL) should still resolve by ISA.

    Spec says: 'Pre-migration rows (stcn NULL) should still resolve by ISA.'
    Production row ``b1`` (the only one with claims) has ST02 NULL because
    the migration's backfill only ran over rows whose raw_result_json
    envelope had the ST02 key — and that row was written before the
    parser populated it.
    """
    with db_mod.SessionLocal()() as s:
        _make_batch(s, id="b3", icn="ISA000003")  # no stcn
    idx = batch_envelope_index()
    assert idx.get("ISA000003") == "b3"
    assert idx.get("ST000003") is None


def test_index_ignores_non_837_batches():
    """835 batches don't contribute to the 999 join index.

    The D10 two-pass join is specifically for 837 → 999 linkage; 835
    remittances live on the response side of the loop and have no ST02
    join key. Filtering by ``kind == "837p"`` keeps the index scoped
    correctly and avoids an 835 row shadowing an 837 ST02 by accident.
    """
    with db_mod.SessionLocal()() as s:
        # Add an 837 row first so we can prove the 835 doesn't leak in.
        _make_batch(s, id="b-837", icn="ISA837", stcn="ST837")
        # And an 835 row whose ISA13 / ST02 would otherwise pollute.
        s.add(Batch(
            id="b-835",
            kind="835",
            input_filename="b-835.x12",
            parsed_at=datetime.now(timezone.utc),
            raw_result_json={"envelope": {"control_number": "ISA999"}},
            transaction_set_control_number="ST999",
        ))
        s.commit()
    idx = batch_envelope_index()
    # 837 row resolves both ways.
    assert idx.get("ISA837") == "b-837"
    assert idx.get("ST837") == "b-837"
    # 835 row contributes nothing.
    assert "ISA999" not in idx
    assert "ST999" not in idx
