from fastapi import APIRouter, Depends, Query, status, HTTPException
from sqlalchemy.orm import Session
from typing import Optional
from utils.utils import get_db, ServiceType, InvoiceStatus, PaymentMethod
from . import handler
from .schema import (
    ServiceCreate, ServiceUpdate, ServiceResponse, ServiceListResponse,
    InvoiceCreate, InvoiceUpdate, InvoiceResponse, InvoiceListResponse, InvoiceDetailResponse,
    InvoicelineitemCreate, InvoicelineitemUpdate, InvoicelineitemResponse, InvoicelineitemListResponse,
    PaymentCreate, PaymentUpdate, PaymentResponse, PaymentListResponse,
    ProcessPaymentRequest, IssueInvoiceRequest,
)

router = APIRouter(prefix="/billing", tags=["Billing"])


# Service routes
@router.post(
    "/services",
    response_model=ServiceResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Service",
    description="Creates a new service in the catalog. Validates that the referenced department exists if department_id is provided. Returns 409 if service already exists.",
)
def create_service_route(data: ServiceCreate, db: Session = Depends(get_db)):
    return handler.create_service(db, data)


@router.get(
    "/services/{entity_id}",
    response_model=ServiceResponse,
    summary="Get Service",
    description="Retrieves a single service by ID. Returns 404 if service not found.",
)
def get_service_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_service(db, entity_id)


@router.get(
    "/services",
    response_model=ServiceListResponse,
    summary="List Services",
    description="Returns a paginated list of services. Supports optional filtering by is_active, service_type, and department_id.",
)
def list_services_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    is_active: Optional[bool] = None,
    service_type: Optional[ServiceType] = None,
    department_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_services(db, limit, offset, is_active=is_active, service_type=service_type, department_id=department_id)


@router.put(
    "/services/{entity_id}",
    response_model=ServiceResponse,
    summary="Update Service",
    description="Updates an existing service. Only provided fields are updated. Returns 404 if service not found, 409 if unique constraint violated.",
)
def update_service_route(entity_id: str, data: ServiceUpdate, db: Session = Depends(get_db)):
    return handler.update_service(db, entity_id, data)


@router.delete(
    "/services/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Service",
    description="Deletes a service. Returns 404 if service not found, 409 if service is referenced by invoice line items.",
)
def delete_service_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_service(db, entity_id)


# Invoice routes
@router.post(
    "/invoices",
    response_model=InvoiceResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Invoice",
    description="Creates a new invoice record. Validates that referenced patient and appointment exist. Returns 409 if invoice_number already exists.",
)
def create_invoice_route(data: InvoiceCreate, db: Session = Depends(get_db)):
    return handler.create_invoice(db, data)


@router.get(
    "/invoices/{entity_id}",
    response_model=InvoiceResponse,
    summary="Get Invoice",
    description="Retrieves a single invoice by ID. Returns 404 if invoice not found.",
)
def get_invoice_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_invoice(db, entity_id)


@router.get(
    "/invoices/{entity_id}/details",
    response_model=InvoiceDetailResponse,
    summary="Get Invoice Details",
    description="Retrieves full invoice details including patient information, appointment details, line items with services, and all payments.",
)
def get_invoice_details_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_invoice_details(db, entity_id)


@router.get(
    "/invoices",
    response_model=InvoiceListResponse,
    summary="List Invoices",
    description="Returns a paginated list of invoices. Supports optional filtering by status, patient_id, and appointment_id.",
)
def list_invoices_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    status_filter: Optional[InvoiceStatus] = None,
    patient_id: Optional[str] = None,
    appointment_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_invoices(db, limit, offset, status_filter=status_filter, patient_id=patient_id, appointment_id=appointment_id)


@router.put(
    "/invoices/{entity_id}",
    response_model=InvoiceResponse,
    summary="Update Invoice",
    description="Updates an existing invoice. Only provided fields are updated. Returns 404 if invoice not found.",
)
def update_invoice_route(entity_id: str, data: InvoiceUpdate, db: Session = Depends(get_db)):
    return handler.update_invoice(db, entity_id, data)


@router.delete(
    "/invoices/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Invoice",
    description="Deletes an invoice. Returns 404 if invoice not found, 409 if invoice is referenced by payments.",
)
def delete_invoice_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_invoice(db, entity_id)


@router.post(
    "/invoices/{entity_id}/issue",
    response_model=InvoiceResponse,
    summary="Issue Invoice",
    description="Changes invoice status from draft to issued. Only draft invoices can be issued. Returns 400 if invoice is not in draft status.",
)
def issue_invoice_route(entity_id: str, data: IssueInvoiceRequest, db: Session = Depends(get_db)):
    return handler.issue_invoice(db, entity_id, data)


# InvoiceLineItem routes
@router.post(
    "/invoice-line-items",
    response_model=InvoicelineitemResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Invoice Line Item",
    description="Creates a new line item for an invoice. Validates that referenced invoice and service exist.",
)
def create_invoicelineitem_route(data: InvoicelineitemCreate, db: Session = Depends(get_db)):
    return handler.create_invoicelineitem(db, data)


@router.get(
    "/invoice-line-items/{entity_id}",
    response_model=InvoicelineitemResponse,
    summary="Get Invoice Line Item",
    description="Retrieves a single invoice line item by ID. Returns 404 if line item not found.",
)
def get_invoicelineitem_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_invoicelineitem(db, entity_id)


@router.get(
    "/invoice-line-items",
    response_model=InvoicelineitemListResponse,
    summary="List Invoice Line Items",
    description="Returns a paginated list of invoice line items. Supports optional filtering by invoice_id and service_id.",
)
def list_invoicelineitems_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    invoice_id: Optional[str] = None,
    service_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_invoicelineitems(db, limit, offset, invoice_id=invoice_id, service_id=service_id)


@router.put(
    "/invoice-line-items/{entity_id}",
    response_model=InvoicelineitemResponse,
    summary="Update Invoice Line Item",
    description="Updates an existing invoice line item. Only provided fields are updated. Returns 404 if line item not found.",
)
def update_invoicelineitem_route(entity_id: str, data: InvoicelineitemUpdate, db: Session = Depends(get_db)):
    return handler.update_invoicelineitem(db, entity_id, data)


@router.delete(
    "/invoice-line-items/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Invoice Line Item",
    description="Deletes an invoice line item. Returns 404 if line item not found.",
)
def delete_invoicelineitem_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_invoicelineitem(db, entity_id)


# Payment routes
@router.post(
    "/payments",
    response_model=PaymentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Payment",
    description="Creates a new payment record. Validates that referenced invoice and patient exist and that payment amount does not exceed balance due.",
)
def create_payment_route(data: PaymentCreate, db: Session = Depends(get_db)):
    return handler.create_payment(db, data)


@router.get(
    "/payments/{entity_id}",
    response_model=PaymentResponse,
    summary="Get Payment",
    description="Retrieves a single payment by ID. Returns 404 if payment not found.",
)
def get_payment_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.get_payment(db, entity_id)


@router.get(
    "/payments",
    response_model=PaymentListResponse,
    summary="List Payments",
    description="Returns a paginated list of payments. Supports optional filtering by invoice_id, patient_id, and payment_method.",
)
def list_payments_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    invoice_id: Optional[str] = None,
    patient_id: Optional[str] = None,
    payment_method: Optional[PaymentMethod] = None,
    db: Session = Depends(get_db),
):
    return handler.list_payments(db, limit, offset, invoice_id=invoice_id, patient_id=patient_id, payment_method=payment_method)


@router.put(
    "/payments/{entity_id}",
    response_model=PaymentResponse,
    summary="Update Payment",
    description="Updates an existing payment. Only provided fields are updated. Returns 404 if payment not found.",
)
def update_payment_route(entity_id: str, data: PaymentUpdate, db: Session = Depends(get_db)):
    return handler.update_payment(db, entity_id, data)


@router.delete(
    "/payments/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Payment",
    description="Deletes a payment. Returns 404 if payment not found.",
)
def delete_payment_route(entity_id: str, db: Session = Depends(get_db)):
    return handler.delete_payment(db, entity_id)


@router.post(
    "/payments/process",
    response_model=PaymentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Process Payment",
    description="Processes a payment and automatically updates the invoice status and balance. Validates payment amount does not exceed balance due. Updates invoice status to partially_paid or paid based on remaining balance.",
)
def process_payment_route(data: ProcessPaymentRequest, db: Session = Depends(get_db)):
    return handler.process_payment(db, data)