import json
from datetime import date
from decimal import Decimal
from pathlib import Path

import pytest

from cyclone.parsers.models import (
    Address,
    BatchSummary,
    BillingProvider,
    ClaimHeader,
    ClaimOutput,
    Envelope,
    Payer,
    Subscriber,
    ValidationReport,
)
from cyclone.parsers.parse_837 import ParseResult
from cyclone.parsers.writer import write_outputs


def _claim(cid: str) -> ClaimOutput:
    return ClaimOutput(
        claim_id=cid,
        control_number="991102977",
        transaction_date=date(2026, 6, 11),
        billing_provider=BillingProvider(name="X", npi="1234567890", address=Address(line1="1", city="x", state="CO", zip="80000")),
        subscriber=Subscriber(first_name="J", last_name="D", member_id="M", dob=date(1980, 1, 1), gender="M", address=Address(line1="1", city="x", state="CO", zip="80000")),
        payer=Payer(name="P", id="SKCO0"),
        claim=ClaimHeader(claim_id=cid, total_charge=Decimal("100"), place_of_service="12", frequency_code="1", provider_signature="Y", assignment="Y", release_of_info="Y"),
        diagnoses=[],
        service_lines=[],
        validation=ValidationReport(passed=True, errors=[], warnings=[]),
        raw_segments=[],
    )


def _result(*cids: str) -> ParseResult:
    return ParseResult(
        envelope=Envelope(sender_id="X", receiver_id="Y", control_number="991102977", transaction_date=date(2026, 6, 11)),
        claims=[_claim(c) for c in cids],
        summary=BatchSummary(input_file="f", control_number="991102977", transaction_date=date(2026, 6, 11), total_claims=len(cids), passed=len(cids), failed=0),
    )


def test_write_outputs_creates_one_file_per_claim(tmp_path: Path):
    result = _result("C1", "C2")
    paths = write_outputs(result, tmp_path)
    assert len(paths) == 2
    for p in paths:
        assert p.exists()
        assert p.suffix == ".json"
        data = json.loads(p.read_text())
        assert "validation" in data


def test_filename_pattern(tmp_path: Path):
    result = _result("C1")
    paths = write_outputs(result, tmp_path)
    assert paths[0].name == "claim-991102977-20260611-C1.json"


def test_filename_sanitizes_unsafe_chars(tmp_path: Path):
    bad = _claim("C/1:*?")
    result = ParseResult(
        envelope=result.envelope if False else None,  # type: ignore
        claims=[bad],
        summary=BatchSummary(input_file="f", total_claims=1, passed=1, failed=0),
    )  # use explicit envelope
    # Simpler: rebuild
    from cyclone.parsers.models import Envelope as E
    result = ParseResult(
        envelope=E(sender_id="X", receiver_id="Y", control_number="991102977", transaction_date=date(2026, 6, 11)),
        claims=[bad],
        summary=BatchSummary(input_file="f", total_claims=1, passed=1, failed=0),
    )
    paths = write_outputs(result, tmp_path)
    # All non-alnum chars except - and _ replaced with -
    assert all(c.isalnum() or c in "-_" for c in paths[0].stem)


def test_summary_json_written(tmp_path: Path):
    result = _result("C1")
    write_outputs(result, tmp_path)
    summary_path = tmp_path / "summary.json"
    assert summary_path.exists()
    data = json.loads(summary_path.read_text())
    assert data["total_claims"] == 1
    assert data["passed"] == 1
