"""SVC-level 835 reparse with member_id at SVC scope.

Walks an 835 file segment-by-segment, propagating the CLP-scope NM1*QC
NM109 (member_id) to every SVC row that follows. Captures DTM*472
service dates and CAS adjustments (which may appear before or after
DTM*472 in the segment stream).
"""
from dataclasses import dataclass
from datetime import date
from decimal import Decimal
from pathlib import Path

ELEM = "*"
SEG_END = "~"


@dataclass(frozen=True)
class SvcRow:
    src_file: str
    claim_id: str
    member_id: str
    status: str
    procedure: str
    modifiers: str
    charge: Decimal
    paid: Decimal
    units: Decimal
    svc_date: date
    cas_reasons: tuple[str, ...]  # each entry is "GROUP-CODE" (e.g. "OA-18")
    pay_date: date | None


def _split(seg: str) -> list[str]:
    return seg.split(ELEM)


def parse_835_svc(path: str | Path) -> "Iterator[SvcRow]":
    """Yield one SvcRow per SVC segment in `path`."""
    path = Path(path)
    text = path.read_text()
    segments = [s for s in text.split(SEG_END) if s]
    pay_date: date | None = None
    current_claim_id = ""
    current_status = ""
    current_member_id = ""
    i = 0
    while i < len(segments):
        elems = _split(segments[i])
        seg_name = elems[0]
        if seg_name == "DTM" and len(elems) > 2 and elems[1] == "405":
            try:
                pay_date = _ymd(elems[2])
            except ValueError:
                pass
        elif seg_name == "CLP":
            current_claim_id = elems[1] if len(elems) > 1 else ""
            current_status = elems[2] if len(elems) > 2 else ""
            current_member_id = ""
        elif seg_name == "NM1" and len(elems) > 1 and elems[1] == "QC":
            current_member_id = elems[9] if len(elems) > 9 else ""
        elif seg_name == "SVC" and current_claim_id:
            rest = elems[1:]
            comp = rest[0] if rest else ""
            proc_parts = comp.split(":")
            procedure = proc_parts[1] if len(proc_parts) > 1 else ""
            modifiers = ":".join(proc_parts[2:]) if len(proc_parts) > 2 else ""
            charge = _decimal(rest[1]) if len(rest) > 1 else Decimal("0")
            paid = _decimal(rest[2]) if len(rest) > 2 else Decimal("0")
            units = _decimal(rest[3]) if len(rest) > 3 else Decimal("0")
            svc_date, cas_reasons = _walk_for_dtm_and_cas(segments, i)
            yield SvcRow(
                src_file=path.name,
                claim_id=current_claim_id,
                member_id=current_member_id,
                status=current_status,
                procedure=procedure,
                modifiers=modifiers,
                charge=charge,
                paid=paid,
                units=units,
                svc_date=svc_date,
                cas_reasons=cas_reasons,
                pay_date=pay_date,
            )
        i += 1


def _ymd(s: str) -> date:
    y, m, d = int(s[0:4]), int(s[4:6]), int(s[6:8])
    return date(y, m, d)


def _decimal(s: str) -> Decimal:
    try:
        return Decimal(s)
    except Exception:
        return Decimal("0")


def _walk_for_dtm_and_cas(
    segments: list[str], start: int, window: int = 10
) -> tuple[date | None, tuple[str, ...]]:
    """Walk the next `window` segments after SVC. Capture DTM*472 and CAS.

    X12 835 may place DTM*472 before or after CAS segments within a service
    line, so we walk the full window and capture both, breaking only at the
    next SVC or CLP (a new claim/service boundary).
    """
    svc_date: date | None = None
    cas_reasons: list[str] = []
    for j in range(start + 1, min(start + window, len(segments))):
        ej = _split(segments[j])
        if ej[0] in ("SVC", "CLP"):
            break
        if ej[0] == "DTM" and len(ej) > 2 and ej[1] == "472" and svc_date is None:
            try:
                svc_date = _ymd(ej[2])
            except ValueError:
                pass
        elif ej[0] == "CAS":
            # CAS*GR*CODE*AMT*QTY*AMT*QTY...  →  GR-CODE
            if len(ej) >= 3:
                cas_reasons.append(f"{ej[1]}-{ej[2]}")
    return svc_date, tuple(cas_reasons)