from fastapi import APIRouter, Depends, Query, status, HTTPException
from sqlalchemy.orm import Session
from typing import Optional
from utils.utils import get_db, LabTestStatus
from . import handler
from .schema import (
    VitalsignCreate,
    VitalsignUpdate,
    VitalsignResponse,
    VitalsignListResponse,
    ConsultationCreate,
    ConsultationUpdate,
    ConsultationResponse,
    ConsultationListResponse,
    ConsultationDetailResponse,
    PrescriptionCreate,
    PrescriptionUpdate,
    PrescriptionResponse,
    PrescriptionListResponse,
    LabtestCreate,
    LabtestUpdate,
    LabtestResponse,
    LabtestListResponse,
)

router = APIRouter(prefix="/clinical", tags=["Clinical"])


# ======================== Vitalsign Routes ========================
@router.post(
    "/vital-signs",
    response_model=VitalsignResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Vital Sign",
    description="Records a new set of vital signs for a patient. Validates blood pressure consistency and temperature range. Returns 404 if patient or recording user does not exist.",
)
def create_vitalsign_route(data: VitalsignCreate, db: Session = Depends(get_db)):
    return handler.create_vitalsign(db, data)


@router.get(
    "/vital-signs",
    response_model=VitalsignListResponse,
    summary="List Vital Signs",
    description="Returns a paginated list of vital sign records. Supports optional filtering by patient_id and recorded_by_user_id.",
)
def list_vitalsigns_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    patient_id: Optional[str] = None,
    recorded_by_user_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if patient_id:
        filters["patient_id"] = patient_id
    if recorded_by_user_id:
        filters["recorded_by_user_id"] = recorded_by_user_id
    return handler.list_vitalsigns(db, limit, offset, **filters)


@router.get(
    "/vital-signs/{entity_id}",
    response_model=VitalsignResponse,
    summary="Get Vital Sign",
    description="Retrieves a single vital sign record by ID. Returns 404 if not found.",
)
def get_vitalsign_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_vitalsign_by_id(db, entity_id)


@router.put(
    "/vital-signs/{entity_id}",
    response_model=VitalsignResponse,
    summary="Update Vital Sign",
    description="Updates an existing vital sign record. Validates references and constraints. Returns 404 if vital sign not found or 400 for validation errors.",
)
def update_vitalsign_route(entity_id: str, data: VitalsignUpdate, db: Session = Depends(get_db)):
    return handler.update_vitalsign(db, entity_id, data)


@router.delete(
    "/vital-signs/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Vital Sign",
    description="Deletes a vital sign record. Returns 404 if not found or 409 if referenced by other records.",
)
def delete_vitalsign_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_vitalsign(db, entity_id)


# ======================== Consultation Routes ========================
@router.post(
    "/consultations",
    response_model=ConsultationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Consultation",
    description="Creates a new consultation record. Validates patient, doctor, and optional appointment references. Returns 409 if appointment already has a consultation.",
)
def create_consultation_route(data: ConsultationCreate, db: Session = Depends(get_db)):
    return handler.create_consultation(db, data)


@router.get(
    "/consultations",
    response_model=ConsultationListResponse,
    summary="List Consultations",
    description="Returns a paginated list of consultations. Supports optional filtering by patient_id, doctor_id, and appointment_id.",
)
def list_consultations_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    patient_id: Optional[str] = None,
    doctor_id: Optional[str] = None,
    appointment_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if patient_id:
        filters["patient_id"] = patient_id
    if doctor_id:
        filters["doctor_id"] = doctor_id
    if appointment_id:
        filters["appointment_id"] = appointment_id
    return handler.list_consultations(db, limit, offset, **filters)


@router.get(
    "/consultations/{entity_id}",
    response_model=ConsultationResponse,
    summary="Get Consultation",
    description="Retrieves a single consultation record by ID. Returns 404 if not found.",
)
def get_consultation_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_consultation_by_id(db, entity_id)


@router.get(
    "/consultations/{entity_id}/details",
    response_model=ConsultationDetailResponse,
    summary="Get Consultation Details",
    description="Retrieves a consultation with full details including patient, doctor, appointment, prescriptions, and lab tests. Uses eager loading to avoid N+1 queries. Returns 404 if not found.",
)
def get_consultation_details_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_consultation_details(db, entity_id)


@router.put(
    "/consultations/{entity_id}",
    response_model=ConsultationResponse,
    summary="Update Consultation",
    description="Updates an existing consultation record. Validates references. Returns 404 if consultation not found or 409 if appointment already has another consultation.",
)
def update_consultation_route(entity_id: str, data: ConsultationUpdate, db: Session = Depends(get_db)):
    return handler.update_consultation(db, entity_id, data)


@router.delete(
    "/consultations/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Consultation",
    description="Deletes a consultation record and cascades to related prescriptions and lab tests. Returns 404 if not found.",
)
def delete_consultation_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_consultation(db, entity_id)


@router.post(
    "/consultations/{entity_id}/complete",
    response_model=ConsultationResponse,
    summary="Complete Consultation",
    description="Marks a consultation as complete. Requires diagnosis to be entered. Updates related appointment status to completed. Returns 400 if diagnosis is missing or 404 if consultation not found.",
)
def complete_consultation_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.complete_consultation(db, entity_id)


# ======================== Prescription Routes ========================
@router.post(
    "/prescriptions",
    response_model=PrescriptionResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Prescription",
    description="Creates a new prescription record. Validates consultation, patient, and doctor references. Returns 404 if any referenced entity does not exist.",
)
def create_prescription_route(data: PrescriptionCreate, db: Session = Depends(get_db)):
    return handler.create_prescription(db, data)


@router.get(
    "/prescriptions",
    response_model=PrescriptionListResponse,
    summary="List Prescriptions",
    description="Returns a paginated list of prescriptions. Supports optional filtering by patient_id, doctor_id, consultation_id, and is_active status.",
)
def list_prescriptions_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    patient_id: Optional[str] = None,
    doctor_id: Optional[str] = None,
    consultation_id: Optional[str] = None,
    is_active: Optional[bool] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if patient_id:
        filters["patient_id"] = patient_id
    if doctor_id:
        filters["doctor_id"] = doctor_id
    if consultation_id:
        filters["consultation_id"] = consultation_id
    if is_active is not None:
        filters["is_active"] = is_active
    return handler.list_prescriptions(db, limit, offset, **filters)


@router.get(
    "/prescriptions/{entity_id}",
    response_model=PrescriptionResponse,
    summary="Get Prescription",
    description="Retrieves a single prescription record by ID. Returns 404 if not found.",
)
def get_prescription_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_prescription_by_id(db, entity_id)


@router.put(
    "/prescriptions/{entity_id}",
    response_model=PrescriptionResponse,
    summary="Update Prescription",
    description="Updates an existing prescription record. Validates references. Returns 404 if prescription not found or 400 for validation errors.",
)
def update_prescription_route(entity_id: str, data: PrescriptionUpdate, db: Session = Depends(get_db)):
    return handler.update_prescription(db, entity_id, data)


@router.delete(
    "/prescriptions/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Prescription",
    description="Deletes a prescription record. Returns 404 if not found or 409 if referenced by other records.",
)
def delete_prescription_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_prescription(db, entity_id)


# ======================== Labtest Routes ========================
@router.post(
    "/lab-tests",
    response_model=LabtestResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Lab Test",
    description="Creates a new lab test order. Validates patient, doctor, and optional consultation references. Returns 404 if any referenced entity does not exist.",
)
def create_labtest_route(data: LabtestCreate, db: Session = Depends(get_db)):
    return handler.create_labtest(db, data)


@router.get(
    "/lab-tests",
    response_model=LabtestListResponse,
    summary="List Lab Tests",
    description="Returns a paginated list of lab tests. Supports optional filtering by patient_id, doctor_id (ordered_by), consultation_id, and status.",
)
def list_labtests_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    patient_id: Optional[str] = None,
    doctor_id: Optional[str] = None,
    consultation_id: Optional[str] = None,
    status: Optional[LabTestStatus] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if patient_id:
        filters["patient_id"] = patient_id
    if doctor_id:
        filters["doctor_id"] = doctor_id
    if consultation_id:
        filters["consultation_id"] = consultation_id
    if status:
        filters["status"] = status
    return handler.list_labtests(db, limit, offset, **filters)


@router.get(
    "/lab-tests/{entity_id}",
    response_model=LabtestResponse,
    summary="Get Lab Test",
    description="Retrieves a single lab test record by ID. Returns 404 if not found.",
)
def get_labtest_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_labtest_by_id(db, entity_id)


@router.put(
    "/lab-tests/{entity_id}",
    response_model=LabtestResponse,
    summary="Update Lab Test",
    description="Updates an existing lab test record. Validates references and status transitions. Returns 404 if lab test not found or 400 for validation errors.",
)
def update_labtest_route(entity_id: str, data: LabtestUpdate, db: Session = Depends(get_db)):
    return handler.update_labtest(db, entity_id, data)


@router.delete(
    "/lab-tests/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Lab Test",
    description="Deletes a lab test record. Returns 404 if not found or 409 if referenced by other records.",
)
def delete_labtest_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_labtest(db, entity_id)


@router.post(
    "/lab-tests/{entity_id}/collect-sample",
    response_model=LabtestResponse,
    summary="Collect Lab Test Sample",
    description="Records sample collection for a lab test. Updates status to 'sample_collected' and sets collection timestamp. Can only be performed on tests in 'ordered' status. Returns 400 if invalid status or 404 if test not found.",
)
def collect_sample_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.collect_sample(db, entity_id)


@router.post(
    "/lab-tests/{entity_id}/enter-results",
    response_model=LabtestResponse,
    summary="Enter Lab Test Results",
    description="Enters results for a lab test. Updates status to 'completed' and sets result values. Requires sample to be collected first. Returns 400 if sample not collected or test is cancelled, 404 if test not found.",
)
def enter_results_route(
    entity_id: str,
    result_value: str = Query(...),
    result_unit: Optional[str] = Query(None),
    reference_range: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    return handler.enter_results(db, entity_id, result_value, result_unit, reference_range)