"""Direct tests for the ``handle_ta1`` handler (SP27 Task 3).

Locks the handler's contract independent of the scheduler lifecycle
so a regression in the scheduler wiring doesn't hide a regression
in the handler.
"""
from __future__ import annotations

import pytest

from cyclone import db
from cyclone.handlers.handle_ta1 import handle
from cyclone.parsers.exceptions import CycloneParseError


ACCEPTED = (
    "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       "
    "*260520*1750*^*00501*000000001*0*P*:~"
    "TA1*000000001*20260520*1750*A*000*20260520~"
    "IEA*1*000000001~"
)

REJECTED = (
    "ISA*00*          *00*          *ZZ*COMEDASSISTPROG*ZZ*TP11525703     "
    "*260520*1750*^*00501*000000001*0*P*:~"
    "TA1*320293557*260520*2338*R*006~"
    "IEA*0*000000001~"
)


def test_handle_ta1_persists_row_and_returns_count():
    """Accepted TA1 → parse_ta1, claim_count=1, persists ack row with ack_code=A."""
    parser_used, claim_count = handle(ACCEPTED, source_file="accepted.ta1")
    assert parser_used == "parse_ta1"
    assert claim_count == 1

    # Lock the persistence half: a row was added to ta1_acks.
    with db.SessionLocal()() as session:
        rows = (
            session.query(db.Ta1Ack)
            .filter_by(source_batch_id="TA1-000000001")
            .all()
        )
        assert len(rows) == 1
        assert rows[0].ack_code == "A"
        assert rows[0].note_code == "000"
        assert rows[0].control_number == "000000001"


def test_handle_ta1_rejected_persists_with_rejected_ack_code():
    """Rejected TA1 (R ack_code, non-zero note_code) → persists row, R ack_code.

    Note: source_batch_id is derived from the ISA control number
    (``TA1-<ISA13>``), not the TA1 segment's internal ICN. Both
    fixtures share ISA13=000000001, so source_batch_id is the same
    string — but ack_code + note_code differentiate the two rows.
    """
    parser_used, claim_count = handle(REJECTED, source_file="rejected.ta1")
    assert parser_used == "parse_ta1"
    assert claim_count == 1

    # Lock the rejection half: ack_code="R" + note_code="006" persisted.
    # (DB is reset per-test, so this fixture owns exactly one row.)
    with db.SessionLocal()() as session:
        rows = (
            session.query(db.Ta1Ack)
            .filter_by(source_batch_id="TA1-000000001")
            .all()
        )
        assert len(rows) == 1
        assert rows[0].ack_code == "R"
        assert rows[0].note_code == "006"


def test_handle_ta1_missing_segment_raises():
    """No TA1 segment → handler raises ValueError (wraps CycloneParseError)."""
    text = (
        "ISA*00*          *00*          *ZZ*SENDER         *ZZ*RECEIVER       "
        "*260520*1750*^*00501*000000001*0*P*:~"
        "IEA*0*000000001~"
    )
    with pytest.raises((CycloneParseError, ValueError)):
        handle(text, source_file="empty.ta1")


def test_handle_ta1_does_not_create_batches_row():
    """TA1 is an envelope-only ack; no ``batches`` row should be created
    (only ``ta1_acks``)."""
    parser_used, claim_count = handle(ACCEPTED, source_file="accepted.ta1")
    with db.SessionLocal()() as session:
        # Confirm no batch was created. Source_batch_id starts with
        # "TA1-" — search the batches table (which uses UUIDs) for any
        # row that starts with "TA1-".
        from sqlalchemy import select
        stmt = select(db.Batch.__table__.c.id).where(
            db.Batch.__table__.c.id.like("TA1-%")
        )
        rows = session.execute(stmt).all()
        assert rows == []
