"""
Referral partner 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.referral import CommissionEntry, ReferralType
from app.models.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.referral import (
    CommissionEntryResponse,
    CommissionSettleRequest,
    ReferralCreate,
    ReferralResponse,
    ReferralUpdate,
)
from app.services.referral_service import ReferralService

router = APIRouter(prefix="/referrals", tags=["Referrals & Partnerships"])
_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,
        created_by_name=entry.created_by_user.name if entry.created_by_user else None,
    )


@router.get(
    "",
    response_model=PaginatedResponse[ReferralResponse],
    status_code=status.HTTP_200_OK,
    summary="List referral partners",
    description="Retrieve paginated referral partners with optional filtering.",
    dependencies=[Depends(require_permission(PermissionCode.REFERRAL_READ))],
)
async def list_referrals(
    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_type: ReferralType | None = Query(None, description="Filter by referral source type"),
    is_active: bool | None = Query(None, description="Filter by active status"),
    q: str | None = Query(None, description="Search by name, code, or phone"),
) -> PaginatedResponse[ReferralResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    items, total = await _referral_service.list_referrals(
        db,
        lab_id=target_lab_id,
        referral_type=referral_type,
        is_active=is_active,
        search=q,
        page=pagination.page,
        limit=pagination.limit,
    )
    pages = math.ceil(total / pagination.limit) if total > 0 else 1
    return PaginatedResponse(
        data=[ReferralResponse.model_validate(i) for i in items],
        meta={
            "page": pagination.page,
            "limit": pagination.limit,
            "total": total,
            "pages": pages,
        },
    )


@router.post(
    "",
    response_model=SuccessResponse[ReferralResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Create referral partner",
    description="Register a new referring doctor, hospital, clinic, or agent.",
    dependencies=[Depends(require_permission(PermissionCode.REFERRAL_WRITE))],
)
async def create_referral(
    data: ReferralCreate,
    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[ReferralResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    referral = await _referral_service.create_referral(db, target_lab_id, data, actor=current_user)
    return SuccessResponse(
        data=ReferralResponse.model_validate(referral),
        message=f"Referral partner '{referral.name}' created successfully.",
    )


@router.get(
    "/{referral_id}",
    response_model=SuccessResponse[ReferralResponse],
    status_code=status.HTTP_200_OK,
    summary="Get referral partner",
    description="Retrieve details of a specific referral partner.",
    dependencies=[Depends(require_permission(PermissionCode.REFERRAL_READ))],
)
async def get_referral(
    referral_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[ReferralResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    referral = await _referral_service.get_referral(db, referral_id, target_lab_id)
    return SuccessResponse(data=ReferralResponse.model_validate(referral))


@router.patch(
    "/{referral_id}",
    response_model=SuccessResponse[ReferralResponse],
    status_code=status.HTTP_200_OK,
    summary="Update referral partner",
    description="Update referral partner contact details, commission rate, or status.",
    dependencies=[Depends(require_permission(PermissionCode.REFERRAL_WRITE))],
)
async def update_referral(
    referral_id: UUID,
    data: ReferralUpdate,
    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[ReferralResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    referral = await _referral_service.update_referral(
        db, referral_id, target_lab_id, data, actor=current_user
    )
    return SuccessResponse(
        data=ReferralResponse.model_validate(referral),
        message="Referral partner updated successfully.",
    )


@router.delete(
    "/{referral_id}",
    response_model=SuccessResponse[None],
    status_code=status.HTTP_200_OK,
    summary="Delete referral partner",
    description="Soft-delete a referral partner without losing historical commission ledger records.",
    dependencies=[Depends(require_permission(PermissionCode.REFERRAL_WRITE))],
)
async def delete_referral(
    referral_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[None]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    await _referral_service.delete_referral(db, referral_id, target_lab_id, actor=current_user)
    return SuccessResponse(
        data=None,
        message="Referral partner deleted successfully.",
    )


@router.get(
    "/{referral_id}/commissions",
    response_model=PaginatedResponse[CommissionEntryResponse],
    status_code=status.HTTP_200_OK,
    summary="List partner commissions",
    description="Retrieve commission ledger records earned by this partner.",
    dependencies=[Depends(require_permission(PermissionCode.COMMISSION_READ))],
)
async def list_partner_commissions(
    referral_id: UUID,
    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="Lab branch ID"),
    is_settled: bool | None = Query(None, description="Filter by settled status"),
) -> PaginatedResponse[CommissionEntryResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    # Ensure partner exists in branch
    await _referral_service.get_referral(db, referral_id, target_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.post(
    "/{referral_id}/settle-commissions",
    response_model=SuccessResponse[list[CommissionEntryResponse]],
    status_code=status.HTTP_200_OK,
    summary="Bulk settle partner commissions",
    description="Disburse payout for all outstanding unsettled commissions for this partner.",
    dependencies=[Depends(require_permission(PermissionCode.COMMISSION_WRITE))],
)
async def settle_partner_commissions(
    referral_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[list[CommissionEntryResponse]]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    settled_entries = await _referral_service.settle_partner_commissions(
        db,
        referral_id=referral_id,
        lab_id=target_lab_id,
        notes=data.notes,
        actor=current_user,
    )
    return SuccessResponse(
        data=[_map_commission(e) for e in settled_entries],
        message=f"Successfully settled {len(settled_entries)} commission entries.",
    )
