from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional, List
from utils.utils import get_db
from . import handler
from .schema import (
    PaymentCreate, PaymentUpdate, PaymentResponse,
    InvoiceCreate, InvoiceUpdate, InvoiceResponse, InvoiceDetailResponse,
    InvoicelineitemCreate, InvoicelineitemUpdate, InvoicelineitemResponse,
    DiscountCreate, DiscountUpdate, DiscountResponse
)

router = APIRouter(prefix="/payments", tags=["Payment Management"])

# Payment routes
@router.post(
    "/",
    response_model=PaymentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Payment",
    description="Creates a new payment record for a booking. Validates that the booking exists and the payment amount is greater than zero. Returns 404 if the booking is not found.",
)
def create_payment_route(data: PaymentCreate, db: Session = Depends(get_db)):
    return handler.create_payment(db, data)

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

@router.get(
    "/",
    response_model=List[PaymentResponse],
    summary="List Payments",
    description="Returns a paginated list of payments. Supports optional filters for booking_id, payment_status, and payment_method.",
)
def list_payments_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    booking_id: Optional[str] = None,
    payment_status: Optional[str] = None,
    payment_method: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_payments(db, limit, offset, booking_id, payment_status, payment_method)

@router.put(
    "/{payment_id}",
    response_model=PaymentResponse,
    summary="Update Payment",
    description="Updates an existing payment record. Validates that the booking exists if booking_id is updated. Returns 404 if the payment or booking is not found.",
)
def update_payment_route(payment_id: str, data: PaymentUpdate, db: Session = Depends(get_db)):
    return handler.update_payment(db, payment_id, data)

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

# Invoice routes
invoice_router = APIRouter(prefix="/invoices", tags=["Payment Management"])

@invoice_router.post(
    "/",
    response_model=InvoiceResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Invoice",
    description="Creates a new invoice for a booking. Validates that the booking exists and the invoice number is unique. Returns 404 if the booking is not found, 409 if the invoice number already exists.",
)
def create_invoice_route(data: InvoiceCreate, db: Session = Depends(get_db)):
    return handler.create_invoice(db, data)

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

@invoice_router.get(
    "/{invoice_id}/details",
    response_model=InvoiceDetailResponse,
    summary="Get Invoice Details",
    description="Retrieves a single invoice with all line items pre-loaded. Returns 404 if the invoice is not found.",
)
def get_invoice_details_route(invoice_id: str, db: Session = Depends(get_db)):
    return handler.get_invoice_details(db, invoice_id)

@invoice_router.get(
    "/",
    response_model=List[InvoiceResponse],
    summary="List Invoices",
    description="Returns a paginated list of invoices. Supports optional filters for booking_id, invoice_status, and invoice_number.",
)
def list_invoices_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    booking_id: Optional[str] = None,
    invoice_status: Optional[str] = None,
    invoice_number: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_invoices(db, limit, offset, booking_id, invoice_status, invoice_number)

@invoice_router.put(
    "/{invoice_id}",
    response_model=InvoiceResponse,
    summary="Update Invoice",
    description="Updates an existing invoice record. Validates that the booking exists if booking_id is updated and the invoice number is unique if changed. Returns 404 if the invoice or booking is not found, 409 if the invoice number already exists.",
)
def update_invoice_route(invoice_id: str, data: InvoiceUpdate, db: Session = Depends(get_db)):
    return handler.update_invoice(db, invoice_id, data)

@invoice_router.delete(
    "/{invoice_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Invoice",
    description="Deletes an invoice record by ID. Cascades to delete all associated line items. Returns 404 if the invoice is not found.",
)
def delete_invoice_route(invoice_id: str, db: Session = Depends(get_db)):
    return handler.delete_invoice(db, invoice_id)

# Invoice Line Item routes
line_item_router = APIRouter(prefix="/invoice-line-items", tags=["Payment Management"])

@line_item_router.post(
    "/",
    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 the invoice exists and quantity is greater than zero. Returns 404 if the invoice is not found.",
)
def create_line_item_route(data: InvoicelineitemCreate, db: Session = Depends(get_db)):
    return handler.create_line_item(db, data)

@line_item_router.get(
    "/{line_item_id}",
    response_model=InvoicelineitemResponse,
    summary="Get Invoice Line Item",
    description="Retrieves a single invoice line item by ID. Returns 404 if the line item is not found.",
)
def get_line_item_route(line_item_id: str, db: Session = Depends(get_db)):
    return handler.get_line_item(db, line_item_id)

@line_item_router.get(
    "/",
    response_model=List[InvoicelineitemResponse],
    summary="List Invoice Line Items",
    description="Returns a paginated list of invoice line items. Supports optional filter for invoice_id. Results are ordered by item_order.",
)
def list_line_items_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    invoice_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_line_items(db, limit, offset, invoice_id)

@line_item_router.put(
    "/{line_item_id}",
    response_model=InvoicelineitemResponse,
    summary="Update Invoice Line Item",
    description="Updates an existing invoice line item. Validates that the invoice exists if invoice_id is updated. Returns 404 if the line item or invoice is not found.",
)
def update_line_item_route(line_item_id: str, data: InvoicelineitemUpdate, db: Session = Depends(get_db)):
    return handler.update_line_item(db, line_item_id, data)

@line_item_router.delete(
    "/{line_item_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Invoice Line Item",
    description="Deletes an invoice line item by ID. Returns 404 if the line item is not found.",
)
def delete_line_item_route(line_item_id: str, db: Session = Depends(get_db)):
    return handler.delete_line_item(db, line_item_id)

# Discount routes
discount_router = APIRouter(prefix="/discounts", tags=["Payment Management"])

@discount_router.post(
    "/",
    response_model=DiscountResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Discount",
    description="Creates a new discount code. Validates that the discount code is unique and the tour package exists if specified. Returns 404 if the tour package is not found, 409 if the discount code already exists.",
)
def create_discount_route(data: DiscountCreate, db: Session = Depends(get_db)):
    return handler.create_discount(db, data)

@discount_router.get(
    "/{discount_id}",
    response_model=DiscountResponse,
    summary="Get Discount",
    description="Retrieves a single discount record by ID. Returns 404 if the discount is not found.",
)
def get_discount_route(discount_id: str, db: Session = Depends(get_db)):
    return handler.get_discount(db, discount_id)

@discount_router.get(
    "/",
    response_model=List[DiscountResponse],
    summary="List Discounts",
    description="Returns a paginated list of discounts. Supports optional filters for is_active, discount_type, and code search.",
)
def list_discounts_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    is_active: Optional[bool] = None,
    discount_type: Optional[str] = None,
    code: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_discounts(db, limit, offset, is_active, discount_type, code)

@discount_router.put(
    "/{discount_id}",
    response_model=DiscountResponse,
    summary="Update Discount",
    description="Updates an existing discount record. Validates that the discount code is unique if changed and the tour package exists if specified. Returns 404 if the discount or tour package is not found, 409 if the discount code already exists.",
)
def update_discount_route(discount_id: str, data: DiscountUpdate, db: Session = Depends(get_db)):
    return handler.update_discount(db, discount_id, data)

@discount_router.delete(
    "/{discount_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Discount",
    description="Deletes a discount record by ID. Returns 404 if the discount is not found.",
)
def delete_discount_route(discount_id: str, db: Session = Depends(get_db)):
    return handler.delete_discount(db, discount_id)

router.include_router(invoice_router)
router.include_router(line_item_router)
router.include_router(discount_router)