"""
Commission ledger management and payout endpoints.
"""

import math
from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.auth_deps import get_current_user, require_permission
from app.core.dependencies import get_db
from app.core.exceptions import ForbiddenException
from app.core.pagination import PaginationParams
from app.core.permissions import PermissionCode
from app.core.responses import PaginatedResponse, SuccessResponse
from app.models.referral import CommissionEntry
from app.models.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.referral import CommissionEntryResponse, CommissionSettleRequest
from app.services.referral_service import ReferralService

router = APIRouter(prefix="/commissions", tags=["Commission Ledger"])
_referral_service = ReferralService()


async def _resolve_lab_id(
    db: AsyncSession,
    user: User,
    requested_lab_id: UUID | None,
) -> UUID:
    """Resolve and authorize the target branch lab_id."""
    if user.is_superadmin:
        if requested_lab_id:
            return requested_lab_id
        if user.lab_id:
            return user.lab_id
        return await LabRepository().get_default_lab_id(db)

    if not user.lab_id:
        return await LabRepository().get_default_lab_id(db)

    if requested_lab_id and requested_lab_id != user.lab_id:
        raise ForbiddenException("Access denied to another lab branch.")

    return user.lab_id


def _map_commission(entry: CommissionEntry) -> CommissionEntryResponse:
    """Map SQLAlchemy CommissionEntry model to CommissionEntryResponse schema."""
    return CommissionEntryResponse(
        id=entry.id,
        lab_id=entry.lab_id,
        referral_id=entry.referral_id,
        order_id=entry.order_id,
        created_by=entry.created_by,
        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,
        referral_name=entry.referral.name if entry.referral else None,
        order_number=entry.order.order_number if entry.order else None,
        patient_name=entry.order.patient.name if entry.order and entry.order.patient else None,
        patient_code=entry.order.patient.patient_code if entry.order and entry.order.patient else None,
        created_by_name=entry.created_by_user.name if entry.created_by_user else None,
    )


@router.get(
    "",
    response_model=PaginatedResponse[CommissionEntryResponse],
    status_code=status.HTTP_200_OK,
    summary="List commission ledger",
    description="Retrieve paginated commission ledger records across partners for a branch.",
    dependencies=[Depends(require_permission(PermissionCode.COMMISSION_READ))],
)
async def list_commissions(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    pagination: Annotated[PaginationParams, Depends()],
    lab_id: UUID | None = Query(None, description="Filter by lab branch ID"),
    referral_id: UUID | None = Query(None, description="Filter by referral partner ID"),
    is_settled: bool | None = Query(None, description="Filter by settled payout status"),
) -> PaginatedResponse[CommissionEntryResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    items, total = await _referral_service.list_commissions(
        db,
        lab_id=target_lab_id,
        referral_id=referral_id,
        is_settled=is_settled,
        page=pagination.page,
        limit=pagination.limit,
    )
    pages = math.ceil(total / pagination.limit) if total > 0 else 1
    return PaginatedResponse(
        data=[_map_commission(i) for i in items],
        meta={
            "page": pagination.page,
            "limit": pagination.limit,
            "total": total,
            "pages": pages,
        },
    )


@router.get(
    "/{entry_id}",
    response_model=SuccessResponse[CommissionEntryResponse],
    status_code=status.HTTP_200_OK,
    summary="Get commission entry",
    description="Retrieve a specific commission ledger entry by ID.",
    dependencies=[Depends(require_permission(PermissionCode.COMMISSION_READ))],
)
async def get_commission_entry(
    entry_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Lab branch ID"),
) -> SuccessResponse[CommissionEntryResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    entry = await _referral_service.get_commission_entry(db, entry_id, target_lab_id)
    return SuccessResponse(data=_map_commission(entry))


@router.post(
    "/{entry_id}/settle",
    response_model=SuccessResponse[CommissionEntryResponse],
    status_code=status.HTTP_200_OK,
    summary="Settle commission entry",
    description="Disburse payout for an individual commission entry.",
    dependencies=[Depends(require_permission(PermissionCode.COMMISSION_WRITE))],
)
async def settle_commission_entry(
    entry_id: UUID,
    data: CommissionSettleRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Lab branch ID"),
) -> SuccessResponse[CommissionEntryResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    entry = await _referral_service.settle_commission_entry(
        db,
        entry_id=entry_id,
        lab_id=target_lab_id,
        notes=data.notes,
        actor=current_user,
    )
    return SuccessResponse(
        data=_map_commission(entry),
        message="Commission entry settled successfully.",
    )
