"""
Payment transaction management 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.billing import Payment, PaymentMode
from app.models.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.billing import PaymentResponse
from app.services.payment_service import PaymentService

router = APIRouter(prefix="/payments", tags=["Payments & Settlements"])
_payment_service = PaymentService()


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_payment(payment: Payment) -> PaymentResponse:
    """Map SQLAlchemy Payment model to PaymentResponse schema."""
    return PaymentResponse(
        id=payment.id,
        lab_id=payment.lab_id,
        bill_id=payment.bill_id,
        received_by=payment.received_by,
        amount=payment.amount,
        payment_mode=payment.payment_mode,
        transaction_reference=payment.transaction_reference,
        paid_at=payment.paid_at,
        notes=payment.notes,
        created_at=payment.created_at,
        updated_at=payment.updated_at,
        received_by_name=payment.received_by_user.name if payment.received_by_user else None,
    )


@router.get(
    "",
    response_model=PaginatedResponse[PaymentResponse],
    status_code=status.HTTP_200_OK,
    summary="List payments",
    description="Retrieve paginated payment transactions for a lab branch with optional mode filter.",
    dependencies=[Depends(require_permission(PermissionCode.PAYMENT_READ))],
)
async def list_payments(
    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"),
    payment_mode: PaymentMode | None = Query(None, description="Filter by payment tender mode"),
) -> PaginatedResponse[PaymentResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    items, total = await _payment_service.list_payments(
        db,
        lab_id=target_lab_id,
        payment_mode=payment_mode,
        page=pagination.page,
        limit=pagination.limit,
    )
    pages = math.ceil(total / pagination.limit) if total > 0 else 1
    return PaginatedResponse(
        data=[_map_payment(p) for p in items],
        meta={
            "page": pagination.page,
            "limit": pagination.limit,
            "total": total,
            "pages": pages,
        },
    )


@router.get(
    "/{payment_id}",
    response_model=SuccessResponse[PaymentResponse],
    status_code=status.HTTP_200_OK,
    summary="Get payment receipt",
    description="Retrieve detailed payment transaction by ID.",
    dependencies=[Depends(require_permission(PermissionCode.PAYMENT_READ))],
)
async def get_payment(
    payment_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[PaymentResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    payment = await _payment_service.get_payment(db, payment_id, target_lab_id)
    return SuccessResponse(data=_map_payment(payment))
