"""
Per-report commission ledger for staff radiologists.

Accrued once when a report verified by a radiologist is released, mirroring
the referral commission engine: rate snapshot from `User.commission_rate`,
base from the bill total (fallback: order price snapshot).
"""

import math
from datetime import UTC, datetime
from decimal import ROUND_HALF_UP, Decimal
from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession

from app.core.exceptions import NotFoundException
from app.core.responses import PaginatedResponse, PaginationMeta
from app.models.referral import RadiologistCommission
from app.models.user import UserRole
from app.repositories.bill_repository import BillRepository
from app.repositories.order_repository import OrderRepository
from app.repositories.radiologist_commission_repository import RadiologistCommissionRepository
from app.repositories.report_repository import ReportRepository
from app.schemas.referral import RadiologistCommissionResponse


def _quantize(amount: Decimal) -> Decimal:
    return amount.quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)


class RadiologistCommissionService:
    """Business logic for radiologist imaging commissions."""

    def __init__(
        self,
        commission_repo: RadiologistCommissionRepository | None = None,
        report_repo: ReportRepository | None = None,
        order_repo: OrderRepository | None = None,
        bill_repo: BillRepository | None = None,
    ) -> None:
        self.repo = commission_repo or RadiologistCommissionRepository()
        self.report_repo = report_repo or ReportRepository()
        self.order_repo = order_repo or OrderRepository()
        self.bill_repo = bill_repo or BillRepository()

    async def accrue_for_report(
        self, db: AsyncSession, report_id: UUID
    ) -> RadiologistCommissionResponse | None:
        """Create the ledger entry for a released radiologist-verified report.

        Returns None when no commission applies (non-radiologist verifier or
        zero/unset rate). Idempotent per report.
        """
        existing = await self.repo.get_by_report_id(db, report_id)
        if existing:
            return RadiologistCommissionResponse.model_validate(existing)

        report = await self.report_repo.get_by_id(db, report_id)
        if report is None:
            return None

        verifier = report.verifier
        if verifier is None or str(verifier.role) != UserRole.RADIOLOGIST.value:
            return None

        rate = verifier.commission_rate or Decimal("0.00")
        if rate <= Decimal("0.00"):
            return None

        order = await self.order_repo.get_by_id(db, report.order_id)
        if order is None:
            return None

        bill = await self.bill_repo.get_by_order_id(db, order.id, order.lab_id)
        if bill is not None:
            base = bill.total_amount
        else:
            test_sum = sum((ot.price_at_order for ot in order.order_tests), Decimal("0.00"))
            pkg_sum = sum((op.price_at_order for op in order.order_packages), Decimal("0.00"))
            base = test_sum + pkg_sum

        amount = _quantize(base * rate / Decimal("100"))
        entry = RadiologistCommission(
            lab_id=order.lab_id,
            radiologist_id=verifier.id,
            order_id=order.id,
            report_id=report.id,
            order_amount=base,
            commission_rate=rate,
            commission_amount=amount,
        )
        created = await self.repo.create(db, entry)
        await db.commit()
        return RadiologistCommissionResponse.model_validate(created)

    async def list_commissions(
        self,
        db: AsyncSession,
        lab_id: UUID,
        radiologist_id: UUID | None = None,
        is_settled: bool | None = None,
        page: int = 1,
        limit: int = 50,
    ) -> PaginatedResponse[RadiologistCommissionResponse]:
        """List paginated ledger entries for a branch."""
        offset = (page - 1) * limit
        items, total = await self.repo.list_commissions(
            db,
            lab_id=lab_id,
            radiologist_id=radiologist_id,
            is_settled=is_settled,
            offset=offset,
            limit=limit,
        )
        pages = math.ceil(total / limit) if total > 0 else 1
        return PaginatedResponse(
            data=[self._to_response(i) for i in items],
            meta=PaginationMeta(page=page, limit=limit, total=total, pages=pages),
        )

    async def settle_entry(
        self, db: AsyncSession, entry_id: UUID, lab_id: UUID, notes: str | None = None
    ) -> RadiologistCommissionResponse:
        """Disburse payout for a single ledger entry."""
        entry = await self.repo.get_by_id(db, entry_id, lab_id)
        if entry is None:
            raise NotFoundException(message=f"Commission entry '{entry_id}' was not found.")
        entry.is_settled = True
        entry.settled_at = datetime.now(UTC)
        if notes:
            entry.notes = notes
        await db.commit()
        await db.refresh(entry)
        return self._to_response(entry)

    @staticmethod
    def _to_response(entry: RadiologistCommission) -> RadiologistCommissionResponse:
        return RadiologistCommissionResponse(
            id=entry.id,
            lab_id=entry.lab_id,
            radiologist_id=entry.radiologist_id,
            order_id=entry.order_id,
            report_id=entry.report_id,
            order_amount=entry.order_amount,
            commission_rate=entry.commission_rate,
            commission_amount=entry.commission_amount,
            is_settled=entry.is_settled,
            settled_at=entry.settled_at,
            notes=entry.notes,
            created_at=entry.created_at,
            updated_at=entry.updated_at,
            radiologist_name=entry.radiologist.name if entry.radiologist else None,
            order_number=entry.order.order_number if entry.order else None,
        )
