"""
Regression tests for radiologist flow foundations.

Covers: test_category.modality (default + routing), GET /reports?modality
imaging/pathology scoping (mixed visible to both), the imaging-only
specimen guard, commission_rate at user creation, and license_no on /me.
"""

from datetime import date
from decimal import Decimal

import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import create_access_token, hash_password
from app.models.lab import Lab
from app.models.order import OrderStatus, OrderTest, OrderTestStatus, VisitOrder
from app.models.patient import Gender, Patient
from app.models.report import Report, ReportStatus
from app.models.test import CategoryModality
from app.models.test import Test as LabTest
from app.models.test import TestCategory as LabCategory
from app.models.test import TestParameter as LabParameter
from app.models.test import TestResultType as LabResultType
from app.models.user import User, UserRole
from app.repositories.permission_repository import PermissionRepository
from app.repositories.report_repository import ReportRepository
from app.services.pdf_service import PDFReportService


@pytest_asyncio.fixture(autouse=True)
async def seed_perms(db_session: AsyncSession) -> None:
    repo = PermissionRepository()
    await repo.seed_permissions(db_session)


@pytest_asyncio.fixture
async def test_lab(db_session: AsyncSession) -> Lab:
    lab = Lab(name="Modality Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


def _token(user: User) -> str:
    return create_access_token(
        subject=str(user.id),
        extra_claims={"email": user.email, "role": user.role.value, "lab_id": str(user.lab_id)},
    )


async def _superadmin_obj(db_session: AsyncSession, test_lab: Lab) -> User:
    user = User(
        lab_id=test_lab.id,
        name="Split Superadmin",
        phone="9841000099",
        email="split-super@munal.com",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("Pass123!"),
        is_active=True,
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return user


@pytest_asyncio.fixture
async def superadmin(db_session: AsyncSession, test_lab: Lab) -> tuple[User, str]:
    user = User(
        lab_id=test_lab.id,
        name="Super Admin",
        phone="9841000001",
        email="super@munal.com",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("Pass123!"),
        is_active=True,
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return user, _token(user)


@pytest_asyncio.fixture
async def radiologist(db_session: AsyncSession, test_lab: Lab) -> tuple[User, str]:
    user = User(
        lab_id=test_lab.id,
        name="Dr. Radio",
        phone="9841000002",
        email="radio@munal.com",
        role=UserRole.RADIOLOGIST,
        hashed_password=hash_password("Pass123!"),
        is_active=True,
        license_no="NMC 777",
        commission_rate=Decimal("10.00"),
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return user, _token(user)


@pytest_asyncio.fixture
async def catalog(db_session: AsyncSession, test_lab: Lab) -> dict[str, object]:
    """One imaging (X-ray) and one pathology (CBC) test category + test each."""
    imaging_cat = LabCategory(
        lab_id=test_lab.id, name="Radiology", description="X-ray etc.", modality=CategoryModality.IMAGING
    )
    path_cat = LabCategory(lab_id=test_lab.id, name="Hematology", description="Blood work")
    db_session.add_all([imaging_cat, path_cat])
    await db_session.flush()

    xray = LabTest(
        lab_id=test_lab.id,
        category_id=imaging_cat.id,
        name="Chest X-ray",
        code="CXR",
        result_type=LabResultType.TEXT,
        price=Decimal("1200.00"),
    )
    xray_abdomen = LabTest(
        lab_id=test_lab.id,
        category_id=imaging_cat.id,
        name="X-ray Abdomen",
        code="AXR",
        result_type=LabResultType.TEXT,
        price=Decimal("1000.00"),
    )
    cbc = LabTest(
        lab_id=test_lab.id,
        category_id=path_cat.id,
        name="Complete Blood Count",
        code="CBC",
        result_type=LabResultType.COMPOSITE,
        price=Decimal("450.00"),
    )
    db_session.add_all([xray, xray_abdomen, cbc])
    await db_session.flush()
    hgb = LabParameter(test_id=cbc.id, name="Hemoglobin", unit="g/dL", decimal_places=1, sort_order=1)
    db_session.add(hgb)
    await db_session.commit()
    # Fresh identity map: same-session reuse after direct-model setup would
    # otherwise serve stale noload collections (production uses per-request
    # sessions, so this only affects test setup).
    db_session.expunge_all()
    return {
        "imaging_cat": imaging_cat,
        "path_cat": path_cat,
        "xray": xray,
        "xray_abdomen": xray_abdomen,
        "cbc": cbc,
    }


async def _make_order(
    db_session: AsyncSession, test_lab: Lab, tests: list[LabTest], number: str
) -> VisitOrder:
    """Direct-model order with one DRAFT report per discipline side (mirrors the service)."""
    patient = Patient(
        lab_id=test_lab.id,
        patient_code=f"P26-{number}",
        name=f"Patient {number}",
        gender=Gender.MALE,
        date_of_birth=date(1990, 1, 1),
        phone=f"984200{number}",
    )
    db_session.add(patient)
    await db_session.flush()
    order = VisitOrder(
        lab_id=test_lab.id,
        patient_id=patient.id,
        order_number=f"ORD-MOD-{number}",
        status=OrderStatus.PENDING,
    )
    db_session.add(order)
    await db_session.flush()
    sides: set[str] = set()
    for t in tests:
        db_session.add(
            OrderTest(order_id=order.id, test_id=t.id, price_at_order=t.price, status=OrderTestStatus.DRAFT)
        )
    await db_session.flush()

    cat_rows = (
        await db_session.execute(
            select(LabCategory.modality).where(
                LabCategory.id.in_({t.category_id for t in tests}),
                LabCategory.deleted_at.is_(None),
            )
        )
    ).all()
    sides = {m.value if hasattr(m, "value") else str(m) for (m,) in cat_rows} or {"pathology"}
    for side in sides:
        db_session.add(
            Report(
                order_id=order.id,
                modality=CategoryModality(side),
                version=1,
                status=ReportStatus.DRAFT,
            )
        )
    await db_session.commit()
    await db_session.refresh(order)
    return order


@pytest_asyncio.fixture
async def orders(
    db_session: AsyncSession, test_lab: Lab, catalog: dict[str, object]
) -> dict[str, VisitOrder]:
    imaging = await _make_order(db_session, test_lab, [catalog["xray"]], "001")  # type: ignore[arg-type]
    pathology = await _make_order(db_session, test_lab, [catalog["cbc"]], "002")  # type: ignore[arg-type]
    mixed = await _make_order(
        db_session,
        test_lab,
        [catalog["xray"], catalog["cbc"]],
        "003",  # type: ignore[arg-type]
    )
    # Fresh identity map (same rationale as the catalog fixture).
    db_session.expunge_all()
    return {"imaging": imaging, "pathology": pathology, "mixed": mixed}


def _numbers(body: dict) -> set[str]:
    return {r["order_number"] for r in body["data"]}


async def _report_id(client: AsyncClient, headers: dict[str, str], order_number: str) -> str:
    res = await client.get("/api/v1/reports", headers=headers)
    assert res.status_code == 200, res.text
    for r in res.json()["data"]:
        if r["order_number"] == order_number:
            return str(r["id"])
    raise AssertionError(f"no report found for order {order_number}")


@pytest.mark.asyncio
async def test_category_modality_defaults_and_updates(
    client: AsyncClient, superadmin: tuple[User, str]
) -> None:
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}

    created = await client.post("/api/v1/test-categories", json={"name": "Plain Cat"}, headers=headers)
    assert created.status_code == 201, created.text
    assert created.json()["data"]["modality"] == "pathology"
    cat_id = created.json()["data"]["id"]

    updated = await client.patch(
        f"/api/v1/test-categories/{cat_id}", json={"modality": "imaging"}, headers=headers
    )
    assert updated.status_code == 200, updated.text
    assert updated.json()["data"]["modality"] == "imaging"

    bad = await client.patch(
        f"/api/v1/test-categories/{cat_id}", json={"modality": "nuclear"}, headers=headers
    )
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_reports_modality_scoping(
    client: AsyncClient, radiologist: tuple[User, str], orders: dict[str, VisitOrder]
) -> None:
    _, token = radiologist
    headers = {"Authorization": f"Bearer {token}"}

    imaging = await client.get("/api/v1/reports?modality=imaging", headers=headers)
    assert imaging.status_code == 200, imaging.text
    assert _numbers(imaging.json()) == {"ORD-MOD-001", "ORD-MOD-003"}
    assert {r["modality"] for r in imaging.json()["data"]} == {"imaging"}

    pathology = await client.get("/api/v1/reports?modality=pathology", headers=headers)
    assert pathology.status_code == 200, pathology.text
    assert _numbers(pathology.json()) == {"ORD-MOD-002", "ORD-MOD-003"}
    assert {r["modality"] for r in pathology.json()["data"]} == {"pathology"}
    # Mixed orders surface once per side — never a shared row.
    assert len([r for r in imaging.json()["data"] if r["order_number"] == "ORD-MOD-003"]) == 1

    everything = await client.get("/api/v1/reports", headers=headers)
    assert _numbers(everything.json()) == {"ORD-MOD-001", "ORD-MOD-002", "ORD-MOD-003"}

    bad = await client.get("/api/v1/reports?modality=nuclear", headers=headers)
    assert bad.status_code == 422


@pytest.mark.asyncio
async def test_specimen_guard_blocks_imaging_only(
    client: AsyncClient, superadmin: tuple[User, str], orders: dict[str, VisitOrder]
) -> None:
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}

    blocked = await client.post(
        f"/api/v1/orders/{orders['imaging'].id}/samples",
        json={"sample_type": "blood"},
        headers=headers,
    )
    assert blocked.status_code == 422, blocked.text
    assert "Imaging-only" in blocked.json()["error"]["message"]

    allowed = await client.post(
        f"/api/v1/orders/{orders['mixed'].id}/samples",
        json={"sample_type": "blood"},
        headers=headers,
    )
    assert allowed.status_code == 201, allowed.text

    pathology_ok = await client.post(
        f"/api/v1/orders/{orders['pathology'].id}/samples",
        json={"sample_type": "blood"},
        headers=headers,
    )
    assert pathology_ok.status_code == 201, pathology_ok.text


@pytest.mark.asyncio
async def test_user_create_with_commission_rate(client: AsyncClient, superadmin: tuple[User, str]) -> None:
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}

    created = await client.post(
        "/api/v1/users",
        json={
            "name": "Dr. New Radio",
            "phone": "9841000009",
            "role": "radiologist",
            "password": "Pass123!",
            "license_no": "NMC 555",
            "commission_rate": "12.50",
        },
        headers=headers,
    )
    assert created.status_code == 201, created.text
    data = created.json()["data"]
    assert data["license_no"] == "NMC 555"
    assert Decimal(str(data["commission_rate"])) == Decimal("12.50")


@pytest.mark.asyncio
async def test_radiologist_self_verifies_imaging(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    catalog: dict[str, object],
    radiologist: tuple[User, str],
    orders: dict[str, VisitOrder],
) -> None:
    """Radiologists verify their own imaging reports with per-study sections."""

    _, token = radiologist
    headers = {"Authorization": f"Bearer {token}"}
    report_id = await _report_id(client, headers, "ORD-MOD-001")
    xray_id_rows = await db_session.execute(
        select(LabTest.id).where(LabTest.code == "CXR", LabTest.lab_id == test_lab.id)
    )
    xray_id = str(xray_id_rows.scalar_one())

    res = await client.post(
        f"/api/v1/reports/{report_id}/verify",
        json={
            "verification_reason": "Normal chest study.",
            "imaging_sections": [{"test_id": xray_id, "findings": "Clear.", "impression": "Normal."}],
        },
        headers=headers,
    )
    assert res.status_code == 200, res.text
    assert res.json()["data"]["status"] == "verified"
    assert res.json()["data"]["modality"] == "imaging"


@pytest.mark.asyncio
async def test_verify_keeps_parameter_gate_for_pathology(
    client: AsyncClient, radiologist: tuple[User, str], orders: dict[str, VisitOrder]
) -> None:
    """Pathology drafts without entered analytes still cannot verify."""
    _, token = radiologist
    headers = {"Authorization": f"Bearer {token}"}
    report_id = await _report_id(client, headers, "ORD-MOD-002")

    res = await client.post(
        f"/api/v1/reports/{report_id}/verify",
        json={"verification_reason": "Looks fine."},
        headers=headers,
    )
    assert res.status_code == 422, res.text


@pytest.mark.asyncio
async def test_resend_released_report(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    superadmin: tuple[User, str],
    radiologist: tuple[User, str],
    orders: dict[str, VisitOrder],
) -> None:
    """Desk re-dispatch: fresh link, audit row, corrected email persisted."""
    from unittest.mock import AsyncMock, patch

    _, rad_token = radiologist
    rad_headers = {"Authorization": f"Bearer {rad_token}"}
    report_id = await _report_id(client, rad_headers, "ORD-MOD-001")
    xray_id_rows = await db_session.execute(
        select(LabTest.id).where(LabTest.code == "CXR", LabTest.lab_id == test_lab.id)
    )
    xray_id = str(xray_id_rows.scalar_one())

    verify = await client.post(
        f"/api/v1/reports/{report_id}/verify",
        json={
            "verification_reason": "Normal chest study.",
            "imaging_sections": [{"test_id": xray_id, "findings": "Clear.", "impression": "Normal."}],
        },
        headers=rad_headers,
    )
    assert verify.status_code == 200, verify.text
    release = await client.post(f"/api/v1/reports/{report_id}/release", json={}, headers=rad_headers)
    assert release.status_code == 200, release.text

    _, sup_token = superadmin
    with patch(
        "app.services.email_service.EmailService.send_email",
        new_callable=AsyncMock,
        return_value=(True, None),
    ):
        resend = await client.post(
            f"/api/v1/reports/{report_id}/resend",
            json={"email": "Corrected@Example.com"},
            headers={"Authorization": f"Bearer {sup_token}"},
        )
    assert resend.status_code == 200, resend.text
    body = resend.json()["data"]
    assert body["recipient"] == "Corrected@example.com"

    # Drafts cannot re-dispatch; radiologists lack the desk permission.
    draft_id = await _report_id(client, rad_headers, "ORD-MOD-002")
    bad = await client.post(
        f"/api/v1/reports/{draft_id}/resend",
        json={"email": "x@example.com"},
        headers={"Authorization": f"Bearer {sup_token}"},
    )
    assert bad.status_code == 422, bad.text
    forbidden = await client.post(
        f"/api/v1/reports/{report_id}/resend",
        json={"email": "x@example.com"},
        headers=rad_headers,
    )
    assert forbidden.status_code == 403, forbidden.text


@pytest.mark.asyncio
async def test_imaging_pdf_renders_narrative_only(
    db_session: AsyncSession, orders: dict[str, VisitOrder]
) -> None:
    """X-ray hardcopy: no analyte tables, no specimen line; impression prints after verify."""

    latest = await ReportRepository().get_latest_by_order_id(db_session, orders["imaging"].id)
    assert latest is not None
    report = await ReportRepository().get_by_id(db_session, latest.id)
    assert report is not None

    html = PDFReportService().render_html(report, "imaging")
    assert "Not applicable (imaging)" in html
    assert "Investigation / Parameter" not in html
    assert "Diagnostic Impression" not in html

    report.verification_reason = "Normal study."
    html2 = PDFReportService().render_html(report, "imaging")
    assert "Diagnostic Impression & Conclusion" in html2
    assert "Normal study." in html2


@pytest.mark.asyncio
async def test_split_creation_per_side(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    catalog: dict[str, object],
    superadmin: tuple[User, str],
) -> None:
    """Booking a mixed order mints one draft report per side; pure orders mint one."""
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}

    patient = Patient(
        lab_id=test_lab.id,
        patient_code="P26-100",
        name="Split Patient",
        gender=Gender.MALE,
        date_of_birth=date(1990, 6, 1),
        phone="984200100",
    )
    db_session.add(patient)
    await db_session.commit()

    created = await client.post(
        "/api/v1/orders",
        json={
            "patient_id": str(patient.id),
            "test_ids": [str(catalog["xray"].id), str(catalog["cbc"].id)],  # type: ignore[attr-defined]
        },
        headers=headers,
    )
    assert created.status_code == 201, created.text
    order_id = created.json()["data"]["id"]

    rows = await client.get("/api/v1/reports", headers=headers)
    sides = {r["modality"] for r in rows.json()["data"] if r["order_id"] == order_id}
    assert sides == {"imaging", "pathology"}

    # Bench entry lands on the pathology side only.
    hgb_rows = await db_session.execute(
        select(LabParameter.id).where(LabParameter.test_id == catalog["cbc"].id)  # type: ignore[attr-defined]
    )
    hgb_id = str(hgb_rows.scalar_one())
    entered = await client.post(
        f"/api/v1/orders/results?order_identifier={order_id}",
        json={"results": [{"parameter_id": hgb_id, "value": "14.2"}]},
        headers=headers,
    )
    assert entered.status_code == 200, entered.text

    imaging = await client.get("/api/v1/reports?modality=imaging", headers=headers)
    pathology = await client.get("/api/v1/reports?modality=pathology", headers=headers)
    imaging_row = next(r for r in imaging.json()["data"] if r["order_id"] == order_id)
    pathology_row = next(r for r in pathology.json()["data"] if r["order_id"] == order_id)
    imaging_detail = await client.get(f"/api/v1/reports/{imaging_row['id']}", headers=headers)
    pathology_detail = await client.get(f"/api/v1/reports/{pathology_row['id']}", headers=headers)
    assert imaging_detail.json()["data"]["result_data"] is None
    assert pathology_detail.json()["data"]["result_data"] is not None

    # Worksheet hides imaging panels from the bench.
    sheet = await client.get(f"/api/v1/orders/results/worksheet?order_identifier={order_id}", headers=headers)
    assert sheet.status_code == 200, sheet.text
    assert {t["test_code"] for t in sheet.json()["data"]["tests"]} == {"CBC"}


@pytest.mark.asyncio
async def test_attach_new_side_mints_draft(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    catalog: dict[str, object],
    superadmin: tuple[User, str],
) -> None:
    """Attaching an X-ray to a lab order opens the missing imaging side."""
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}
    patient = Patient(
        lab_id=test_lab.id,
        patient_code="P26-101",
        name="Attach Patient",
        gender=Gender.FEMALE,
        date_of_birth=date(1995, 2, 2),
        phone="984200101",
    )
    db_session.add(patient)
    await db_session.commit()

    created = await client.post(
        "/api/v1/orders",
        json={"patient_id": str(patient.id), "test_ids": [str(catalog["cbc"].id)]},  # type: ignore[attr-defined]
        headers=headers,
    )
    assert created.status_code == 201, created.text
    order_id = created.json()["data"]["id"]

    attached = await client.post(
        f"/api/v1/orders/{order_id}/tests",
        json={"test_ids": [str(catalog["xray"].id)]},  # type: ignore[attr-defined]
        headers=headers,
    )
    assert attached.status_code == 200, attached.text

    rows = await client.get("/api/v1/reports", headers=headers)
    sides = {r["modality"] for r in rows.json()["data"] if r["order_id"] == order_id}
    assert sides == {"pathology", "imaging"}
    imaging_row = next(
        r for r in rows.json()["data"] if r["order_id"] == order_id and r["modality"] == "imaging"
    )
    assert imaging_row["status"] == "draft"
    assert imaging_row["version"] == 1


@pytest.mark.asyncio
async def test_amend_versions_per_side(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    radiologist: tuple[User, str],
    orders: dict[str, VisitOrder],
) -> None:
    """Amending the imaging side versions independently of pathology."""

    _, token = radiologist
    headers = {"Authorization": f"Bearer {token}"}
    xray_id_rows = await db_session.execute(
        select(LabTest.id).where(LabTest.code == "CXR", LabTest.lab_id == test_lab.id)
    )
    xray_id = str(xray_id_rows.scalar_one())

    # The listed ORD-MOD-003 rows are per-side now: imaging + pathology.
    rows = await client.get("/api/v1/reports", headers=headers)
    by_number = [r for r in rows.json()["data"] if r["order_number"] == "ORD-MOD-003"]
    assert {r["modality"] for r in by_number} == {"imaging", "pathology"}
    imaging_row = next(r for r in by_number if r["modality"] == "imaging")

    # Only the imaging side verifies without analytes; amend it once.
    verify = await client.post(
        f"/api/v1/reports/{imaging_row['id']}/verify",
        json={
            "verification_reason": "First read.",
            "imaging_sections": [{"test_id": xray_id, "findings": "Clear.", "impression": "Normal."}],
        },
        headers=headers,
    )
    assert verify.status_code == 200, verify.text
    amend = await client.post(
        f"/api/v1/reports/{imaging_row['id']}/amend",
        json={"reason": "Addendum: correlate clinically."},
        headers=headers,
    )
    assert amend.status_code == 200, amend.text
    assert amend.json()["data"]["version"] == 2
    assert amend.json()["data"]["modality"] == "imaging"

    lineage_all = await client.get(f"/api/v1/reports/order/{orders['mixed'].id}/versions", headers=headers)
    assert lineage_all.status_code == 200
    assert len(lineage_all.json()["data"]) == 3
    lineage_side = await client.get(
        f"/api/v1/reports/order/{orders['mixed'].id}/versions?modality=imaging", headers=headers
    )
    assert lineage_side.status_code == 200
    assert {r["version"] for r in lineage_side.json()["data"]} == {1, 2}
    assert {r["modality"] for r in lineage_side.json()["data"]} == {"imaging"}


@pytest.mark.asyncio
async def test_imaging_pdf_excludes_lab_tables(
    client: AsyncClient, superadmin: tuple[User, str], orders: dict[str, VisitOrder]
) -> None:
    """Mixed-order hardcopies contain only their own side's panels."""
    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}
    rows = await client.get("/api/v1/reports", headers=headers)
    assert rows.status_code == 200, rows.text
    by_side = {r["modality"]: r for r in rows.json()["data"] if r["order_number"] == "ORD-MOD-003"}
    assert set(by_side) == {"imaging", "pathology"}

    imaging_preview = await client.get(f"/api/v1/reports/{by_side['imaging']['id']}/preview", headers=headers)
    assert imaging_preview.status_code == 200, imaging_preview.text
    assert "Complete Blood Count" not in imaging_preview.text
    assert "Investigation / Parameter" not in imaging_preview.text
    assert "Not applicable (imaging)" in imaging_preview.text

    pathology_preview = await client.get(
        f"/api/v1/reports/{by_side['pathology']['id']}/preview", headers=headers
    )
    assert pathology_preview.status_code == 200, pathology_preview.text
    assert "Complete Blood Count" in pathology_preview.text


@pytest.mark.asyncio
async def test_imaging_verify_requires_full_section_coverage(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    catalog: dict[str, object],
    radiologist: tuple[User, str],
) -> None:
    """Every ordered imaging study needs its own findings + impression."""
    _, token = radiologist
    headers = {"Authorization": f"Bearer {token}"}
    two_study = await _make_order(
        db_session,
        test_lab,
        [catalog["xray"], catalog["xray_abdomen"]],
        "010",  # type: ignore[arg-type]
    )
    report_id = await _report_id(client, headers, two_study.order_number)
    xray_id = str(catalog["xray"].id)  # type: ignore[attr-defined]
    abdomen_id = str(catalog["xray_abdomen"].id)  # type: ignore[attr-defined]

    partial = await client.post(
        f"/api/v1/reports/{report_id}/verify",
        json={
            "verification_reason": "Overall clear.",
            "imaging_sections": [{"test_id": xray_id, "findings": "Clear.", "impression": "Normal."}],
        },
        headers=headers,
    )
    assert partial.status_code == 422, partial.text

    full = await client.post(
        f"/api/v1/reports/{report_id}/verify",
        json={
            "verification_reason": "Overall clear.",
            "imaging_sections": [
                {"test_id": xray_id, "findings": "Clear.", "impression": "Normal."},
                {"test_id": abdomen_id, "findings": "No obstruction.", "impression": "Normal."},
            ],
        },
        headers=headers,
    )
    assert full.status_code == 200, full.text
    body = full.json()["data"]
    assert body["status"] == "verified"
    assert "[CXR] Clear." in (body["notes"] or "")


@pytest.mark.asyncio
async def test_track_mixed_order_per_side_documents(
    client: AsyncClient, orders: dict[str, VisitOrder]
) -> None:
    """Public tracking exposes one document state per side of a mixed order."""
    res = await client.get(
        "/api/v1/client/orders/track", params={"order_number": "ORD-MOD-003", "phone": "984200003"}
    )
    assert res.status_code == 200, res.text
    body = res.json()["data"]
    assert {d["modality"] for d in body["documents"]} == {"imaging", "pathology"}
    assert all(d["ready"] is False for d in body["documents"])
    assert body["report_ready"] is False


@pytest.mark.asyncio
async def test_bill_pin_unified_format(
    client: AsyncClient,
    db_session: AsyncSession,
    test_lab: Lab,
    catalog: dict[str, object],
    superadmin: tuple[User, str],
) -> None:
    """Bills issue unambiguous alphanumeric PINs with a matching encrypted copy."""
    import re

    from app.core.portal_pin import decrypt_pin

    _, token = superadmin
    headers = {"Authorization": f"Bearer {token}"}
    patient = Patient(
        lab_id=test_lab.id,
        patient_code="P26-200",
        name="PIN Patient",
        gender=Gender.MALE,
        date_of_birth=date(1990, 1, 1),
        phone="984200200",
    )
    db_session.add(patient)
    await db_session.commit()

    order = await client.post(
        "/api/v1/orders",
        json={"patient_id": str(patient.id), "test_ids": [str(catalog["cbc"].id)]},  # type: ignore[attr-defined]
        headers=headers,
    )
    assert order.status_code == 201, order.text
    bill = await client.post("/api/v1/bills", json={"order_id": order.json()["data"]["id"]}, headers=headers)
    assert bill.status_code == 201, bill.text
    pin = bill.json()["data"]["portal_pin"]
    assert re.fullmatch(r"[A-HJ-NP-Z2-9]{6}", pin or ""), pin

    await db_session.refresh(patient, attribute_names=["portal_pin_enc"])
    assert decrypt_pin(patient.portal_pin_enc) == pin


@pytest.mark.asyncio
async def test_auth_me_returns_license_no(client: AsyncClient, radiologist: tuple[User, str]) -> None:
    _, token = radiologist
    me = await client.get("/api/v1/auth/me", headers={"Authorization": f"Bearer {token}"})
    assert me.status_code == 200, me.text
    assert me.json()["data"]["license_no"] == "NMC 777"
