"""Tests for the 270 (Eligibility Benefit Inquiry) Pydantic models.

SP3 Phase 4 (T18): minimal typed shape needed by the parser (T20),
serializer (T22), and ``/api/eligibility/request`` endpoint (T23).
The spec defines richer models (gender, address, etc.), but the v1
round-trip only needs the minimum surface — see the inline rationale
in ``parsers/models_270.py``.
"""
from __future__ import annotations

import json
from datetime import date

import pytest
from pydantic import ValidationError

from cyclone.parsers.models import BatchSummary, Envelope
from cyclone.parsers.models_270 import (
    EligibilityBenefitInquiry,
    InformationReceiver270,
    InformationSource270,
    ParseResult270,
    Patient270,
    Subscriber270,
)


def _build_result() -> ParseResult270:
    return ParseResult270(
        envelope=Envelope(
            sender_id="SUBMITTERID",
            receiver_id="RECEIVERID",
            control_number="000000001",
            transaction_date=date(2024, 1, 1),
            implementation_guide="005010X279A1",
        ),
        information_source=InformationSource270(
            name="PAYER NAME",
            id="SKCO0",
        ),
        information_receiver=InformationReceiver270(
            name="PROVIDER NAME",
            npi="1234567890",
        ),
        subscriber=Subscriber270(
            member_id="MEMBER123",
            first_name="JOHN",
            last_name="DOE",
            dob=date(1980, 1, 1),
        ),
        inquiries=[
            EligibilityBenefitInquiry(service_type_code="1"),
            EligibilityBenefitInquiry(service_type_code="30"),
        ],
        summary=BatchSummary(
            input_file="minimal_270.txt",
            control_number="000000001",
            transaction_date=date(2024, 1, 1),
            total_claims=1,
            passed=1,
            failed=0,
        ),
    )


def test_parse_result_270_minimal_round_trip():
    """Build a minimal ParseResult270 and round-trip via JSON."""
    r = _build_result()
    blob = json.loads(r.model_dump_json())
    assert blob["envelope"]["control_number"] == "000000001"
    assert blob["envelope"]["implementation_guide"] == "005010X279A1"
    assert blob["information_source"]["name"] == "PAYER NAME"
    assert blob["information_source"]["id"] == "SKCO0"
    assert blob["information_receiver"]["npi"] == "1234567890"
    assert blob["subscriber"]["first_name"] == "JOHN"
    assert blob["subscriber"]["last_name"] == "DOE"
    assert blob["subscriber"]["member_id"] == "MEMBER123"
    assert blob["subscriber"]["dob"] == "1980-01-01"
    assert blob["patient"] is None
    assert len(blob["inquiries"]) == 2
    assert blob["inquiries"][0]["service_type_code"] == "1"
    assert blob["inquiries"][1]["service_type_code"] == "30"

    # Round-trip back to the model.
    r2 = ParseResult270.model_validate(blob)
    assert r2.information_source.name == "PAYER NAME"
    assert r2.subscriber.member_id == "MEMBER123"
    assert r2.inquiries[0].service_type_code == "1"
    assert r2.summary.total_claims == 1


def test_eligibility_benefit_inquiry_required_fields():
    """``service_type_code`` is the only required field on the EQ model."""
    # Without it: validation error.
    with pytest.raises(ValidationError) as exc:
        EligibilityBenefitInquiry()  # type: ignore[call-arg]
    assert "service_type_code" in str(exc.value)

    # With it: parses cleanly. ``coverage_info`` is optional.
    ebi = EligibilityBenefitInquiry(service_type_code="1")
    assert ebi.coverage_info is None

    # coverage_info supplied → round-trips.
    ebi2 = EligibilityBenefitInquiry(service_type_code="30", coverage_info="C")
    blob = json.loads(ebi2.model_dump_json())
    assert blob["coverage_info"] == "C"
    assert EligibilityBenefitInquiry.model_validate(blob).coverage_info == "C"


def test_patient_270_optional_fields():
    """Patient270's fields are all optional; relationship carries HL/INS qualifiers."""
    p = Patient270()
    blob = json.loads(p.model_dump_json())
    assert blob["first_name"] is None
    assert blob["relationship"] is None
    p2 = Patient270(first_name="JANE", last_name="DOE", relationship="19")  # 19 = child
    assert p2.relationship == "19"


def test_parse_result_270_inquiries_default_empty():
    """Inquiries default to an empty list when omitted (Pydantic default_factory)."""
    r = ParseResult270(
        envelope=Envelope(
            sender_id="S", receiver_id="R", control_number="000000001",
            transaction_date=date(2024, 1, 1),
        ),
        information_source=InformationSource270(name="P"),
        information_receiver=InformationReceiver270(name="P"),
        subscriber=Subscriber270(member_id="M"),
        summary=BatchSummary(input_file="", total_claims=0, passed=0, failed=0),
    )
    assert r.inquiries == []
    assert r.patient is None
