"""
Patient management endpoints.

CRUD operations and patient search across name, phone, and patient code.
"""

from datetime import date, datetime
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 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.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.patient import (
    PatientCreate,
    PatientResponse,
    PatientUpdate,
    PortalCredentialsResponse,
    PortalCredentialsUpdate,
)
from app.services.patient_service import PatientService

router = APIRouter(prefix="/patients", tags=["Patients"])
_patient_service = PatientService()


async def _resolve_lab_id(db: AsyncSession, user: User, requested_lab_id: UUID | None) -> UUID:
    """Keep staff within their assigned branch while allowing superadmins explicit scope."""
    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


@router.get(
    "",
    response_model=PaginatedResponse[PatientResponse],
    status_code=status.HTTP_200_OK,
    summary="List and search patients",
    description=(
        "Retrieve paginated list of patients with optional search query by name, phone, or patient code."
    ),
)
async def list_patients(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_READ))],
    pagination: Annotated[PaginationParams, Depends()],
    lab_id: UUID | None = Query(None, description="Filter by lab branch ID"),
    q: str | None = Query(None, description="Search query across name, phone, or patient code"),
    created_from: datetime | None = Query(
        None, description="Registered at or after (inclusive, ISO datetime)"
    ),
    created_to: datetime | None = Query(None, description="Registered before (exclusive, ISO datetime)"),
    activity_date: date | None = Query(
        None,
        description="Include patients registered or active in clinic operations on this Nepal-local date",
    ),
) -> PaginatedResponse[PatientResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    return await _patient_service.list_patients(
        db=db,
        pagination=pagination,
        lab_id=target_lab_id,
        q=q,
        created_from=created_from,
        created_to=created_to,
        activity_date=activity_date,
    )


@router.post(
    "",
    response_model=SuccessResponse[PatientResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Register patient",
    description="Register a new patient record with demographic and contact details.",
)
async def create_patient(
    data: PatientCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_WRITE))],
) -> SuccessResponse[PatientResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, data.lab_id)
    patient = await _patient_service.create_patient(
        db, data.model_copy(update={"lab_id": target_lab_id}), actor=current_user
    )
    return SuccessResponse(
        data=patient,
        message="Patient registered successfully.",
    )


@router.get(
    "/{patient_id}",
    response_model=SuccessResponse[PatientResponse],
    status_code=status.HTTP_200_OK,
    summary="Get patient details",
    description="Retrieve detailed profile for a specific patient.",
)
async def get_patient(
    patient_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_READ))],
) -> SuccessResponse[PatientResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, None)
    patient = await _patient_service.get_patient(db, patient_id, lab_id=target_lab_id)
    return SuccessResponse(data=patient)


@router.patch(
    "/{patient_id}",
    response_model=SuccessResponse[PatientResponse],
    status_code=status.HTTP_200_OK,
    summary="Update patient",
    description="Update patient demographic or contact information.",
)
async def update_patient(
    patient_id: UUID,
    data: PatientUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_WRITE))],
) -> SuccessResponse[PatientResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, None)
    patient = await _patient_service.update_patient(
        db, patient_id, data, actor=current_user, lab_id=target_lab_id
    )
    return SuccessResponse(
        data=patient,
        message="Patient updated successfully.",
    )


@router.patch(
    "/{patient_id}/portal-credentials",
    response_model=SuccessResponse[PortalCredentialsResponse],
    status_code=status.HTTP_200_OK,
    summary="Reset portal login credentials",
    description=(
        "Reception/superadmin reset of the patient portal username (phone) "
        "and/or fresh bill PIN. The PIN is returned once — print it for the patient."
    ),
)
async def reset_portal_credentials(
    patient_id: UUID,
    data: PortalCredentialsUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_WRITE))],
) -> SuccessResponse[PortalCredentialsResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, None)
    patient, portal_pin = await _patient_service.reset_portal_credentials(
        db,
        patient_id,
        data.phone,
        data.rotate_pin,
        actor=current_user,
        lab_id=target_lab_id,
    )
    return SuccessResponse(
        data=PortalCredentialsResponse(patient=patient, portal_pin=portal_pin),
        message="Portal credentials updated successfully.",
    )


@router.delete(
    "/{patient_id}",
    response_model=SuccessResponse[dict[str, str]],
    status_code=status.HTTP_200_OK,
    summary="Delete patient",
    description="Soft delete a patient record.",
)
async def delete_patient(
    patient_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_permission(PermissionCode.PATIENT_WRITE))],
) -> SuccessResponse[dict[str, str]]:
    target_lab_id = await _resolve_lab_id(db, current_user, None)
    await _patient_service.delete_patient(db, patient_id, actor=current_user, lab_id=target_lab_id)
    return SuccessResponse(
        data={"id": str(patient_id)},
        message="Patient deleted successfully.",
    )
