"""Tests for the 999 ACK Pydantic models.

SP3 Phase 3 (T10): minimal typed shape needed by the parser (T11),
serializer (T12), and auto-ACK builder (T15). The spec defines a richer
``FunctionalGroupResponse`` model with nested ``SetHeader`` /
``ElementError`` types, but the actual code paths only need the
``AK1``/``AK2`` headers + ``AK5`` accept/reject + ``AK9`` counts. We keep
the leaner models in this file; richer shapes can be added later without
breaking the existing public API.
"""
from __future__ import annotations

import json
from datetime import date

from cyclone.parsers.models import BatchSummary, Envelope
from cyclone.parsers.models_999 import (
    AcknowledgmentHeader,
    FunctionalGroupAck,
    ParseResult999,
    SegmentContext,
    SegmentError,
    SetAcceptReject,
    SetFunctionalGroupResponse,
)


def _build_result() -> ParseResult999:
    return ParseResult999(
        envelope=Envelope(
            sender_id="RECEIVERID",
            receiver_id="SUBMITTERID",
            control_number="000000001",
            transaction_date=date(2024, 1, 1),
            implementation_guide="005010X231A1",
        ),
        functional_group_acks=[
            FunctionalGroupAck(
                ak1=AcknowledgmentHeader(
                    functional_id_code="HC",
                    group_control_number="0001",
                ),
                received_count=1,
                accepted_count=1,
                rejected_count=0,
                ack_code="A",
            ),
        ],
        set_responses=[
            SetFunctionalGroupResponse(
                ak2=AcknowledgmentHeader(
                    functional_id_code="837",
                    group_control_number="0001",
                ),
                set_control_number="0001",
                transaction_set_identifier="837",
                segment_errors=[],
                set_accept_reject=SetAcceptReject(code="A"),
            ),
        ],
        summary=BatchSummary(
            input_file="minimal_999.txt",
            control_number="000000001",
            transaction_date=date(2024, 1, 1),
            total_claims=1,
            passed=1,
            failed=0,
        ),
    )


def test_parse_result_999_minimal_round_trip():
    """Build a minimal ParseResult999 and round-trip via JSON."""
    r = _build_result()
    blob = json.loads(r.model_dump_json())
    assert blob["envelope"]["control_number"] == "000000001"
    assert blob["functional_group_acks"][0]["ack_code"] == "A"
    assert blob["set_responses"][0]["set_accept_reject"]["code"] == "A"
    # Round-trip back to the model
    r2 = ParseResult999.model_validate(blob)
    assert r2.functional_group_acks[0].received_count == 1
    assert r2.set_responses[0].ak2.functional_id_code == "837"


def test_set_accept_reject_codes():
    """A / R / E / W / X all parse cleanly on SetAcceptReject."""
    for code in ("A", "R", "E", "W", "X"):
        sar = SetAcceptReject(code=code)
        assert sar.code == code
        # round-trip via model_dump
        assert SetAcceptReject.model_validate(sar.model_dump()).code == code


def test_functional_group_ack_counts_serialize():
    """accepted/rejected counts on FunctionalGroupAck round-trip."""
    fg = FunctionalGroupAck(
        ak1=AcknowledgmentHeader(functional_id_code="HC", group_control_number="1"),
        received_count=5,
        accepted_count=3,
        rejected_count=2,
        ack_code="P",  # "partial" — surfaced in AK909
    )
    blob = json.loads(fg.model_dump_json())
    assert blob["received_count"] == 5
    assert blob["accepted_count"] == 3
    assert blob["rejected_count"] == 2
    assert blob["ack_code"] == "P"
    # default values populated
    rebuilt = FunctionalGroupAck.model_validate(blob)
    assert rebuilt.ak1.functional_id_code == "HC"
    assert rebuilt.received_count == 5


def test_segment_error_carries_optional_element_ref():
    """SegmentError.element_position is optional; defaults to None when absent."""
    seg_err = SegmentError(
        context=SegmentContext(
            segment_id="CLM",
            segment_position=12,
            loop_id="2300",
            implementation_convention_ref=None,
        ),
        error_code="8",  # "Segment Exceeds Maximum Use"
    )
    assert seg_err.element_position is None
    assert seg_err.element_reference is None
    # Round-trip
    blob = json.loads(seg_err.model_dump_json())
    assert blob["error_code"] == "8"
    assert blob["element_position"] is None
    rebuilt = SegmentError.model_validate(blob)
    assert rebuilt.context.segment_id == "CLM"
