"""
Tests for radiologist per-report commissions (Phase E).

Rate lives on the radiologist's user profile (superadmin-set);
accrual fires on report release and is idempotent per report.
"""

from datetime import UTC, datetime
from decimal import Decimal

import pytest
import pytest_asyncio
from httpx import AsyncClient
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 Test as LabTest
from app.models.test import TestCategory as LabCategory
from app.models.test import TestResultType as LabResultType
from app.models.user import User, UserRole
from app.repositories.permission_repository import PermissionRepository
from app.services.radiologist_commission_service import RadiologistCommissionService


@pytest_asyncio.fixture(autouse=True)
async def seed_perms(db_session: AsyncSession) -> None:
    """Seed system permissions for RBAC enforcement."""
    repo = PermissionRepository()
    await repo.seed_permissions(db_session)


@pytest_asyncio.fixture
async def comm_lab(db_session: AsyncSession) -> Lab:
    """Create primary test branch lab."""
    lab = Lab(name="Radiologist Commission Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


@pytest_asyncio.fixture
async def admin_token(db_session: AsyncSession, comm_lab: Lab) -> str:
    """Create branch admin token (COMMISSION_READ/WRITE via ADMIN role)."""
    admin = User(
        lab_id=comm_lab.id,
        name="Commission Admin",
        phone="9819200001",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("AdminPass123!"),
        is_active=True,
    )
    db_session.add(admin)
    await db_session.commit()
    await db_session.refresh(admin)

    return create_access_token(
        subject=str(admin.id),
        extra_claims={
            "phone": admin.phone,
            "role": admin.role.value,
            "lab_id": str(comm_lab.id),
        },
    )


@pytest_asyncio.fixture
async def radiologist(db_session: AsyncSession, comm_lab: Lab) -> User:
    """Create radiologist with a 10% commission rate."""
    user = User(
        lab_id=comm_lab.id,
        name="Imaging Doctor",
        phone="9819200002",
        role=UserRole.RADIOLOGIST,
        hashed_password=hash_password("RadioPass123!"),
        is_active=True,
        commission_rate=Decimal("10.00"),
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return user


@pytest_asyncio.fixture
async def priced_order(db_session: AsyncSession, comm_lab: Lab, radiologist: User) -> VisitOrder:
    """Visit order with one priced test and a released radiologist report."""
    patient = Patient(
        lab_id=comm_lab.id,
        patient_code="P/26/0000000091",
        name="Commission Patient",
        gender=Gender.MALE,
        phone="9819200091",
    )
    db_session.add(patient)
    await db_session.flush()

    cat = LabCategory(lab_id=comm_lab.id, name="Imaging")
    db_session.add(cat)
    await db_session.flush()

    test = LabTest(
        lab_id=comm_lab.id,
        category_id=cat.id,
        name="Chest X-Ray",
        code="CXR",
        price=2000.0,
        result_type=LabResultType.NUMERIC,
    )
    db_session.add(test)
    await db_session.flush()

    order = VisitOrder(
        lab_id=comm_lab.id,
        patient_id=patient.id,
        order_number="ORD/26/000091",
        status=OrderStatus.COMPLETED,
    )
    order.order_tests.append(
        OrderTest(
            test_id=test.id,
            price_at_order=test.price,
            status=OrderTestStatus.RELEASED,
        )
    )
    db_session.add(order)
    await db_session.flush()

    report = Report(
        order_id=order.id,
        version=1,
        status=ReportStatus.RELEASED,
        verified_by=radiologist.id,
        verified_at=datetime.now(UTC),
        released_at=datetime.now(UTC),
    )
    db_session.add(report)
    await db_session.commit()
    await db_session.refresh(order)
    return order


@pytest.mark.asyncio
class TestRadiologistCommissions:
    """Accrual on release, idempotency, listing, and settlement."""

    async def test_accrue_release_idempotent_and_settle(
        self, db_session: AsyncSession, comm_lab: Lab, radiologist: User, priced_order: VisitOrder
    ) -> None:
        from app.repositories.report_repository import ReportRepository

        # Fresh session view: the VisitOrder.order_tests collection is
        # lazy="noload", so same-session instances can read stale-empty.
        # Production release requests always run on a fresh session.
        db_session.expunge_all()

        service = RadiologistCommissionService()
        report = await ReportRepository().get_latest_by_order_id(db_session, priced_order.id)
        assert report is not None

        first = await service.accrue_for_report(db_session, report.id)
        assert first is not None
        assert first.commission_rate == Decimal("10.00")
        assert first.commission_amount == Decimal("200.00")

        # Idempotent: second call returns the same entry, no duplicate
        from app.repositories.radiologist_commission_repository import (
            RadiologistCommissionRepository,
        )

        second = await service.accrue_for_report(db_session, first.report_id)
        assert second is not None
        assert second.id == first.id
        entries, _ = await RadiologistCommissionRepository().list_commissions(db_session, comm_lab.id)
        assert len(entries) == 1

        settled = await service.settle_entry(db_session, first.id, comm_lab.id, notes="paid cash")
        assert settled.is_settled is True

    async def test_list_endpoint_filters_unsettled(
        self, client: AsyncClient, admin_token: str, priced_order: VisitOrder
    ) -> None:
        headers = {"Authorization": f"Bearer {admin_token}"}
        res = await client.get(
            "/api/v1/radiologist-commissions",
            params={"is_settled": False},
            headers=headers,
        )
        assert res.status_code == 200, res.text
        assert res.json()["meta"]["total"] >= 0
