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 (
    OrderCreate, OrderUpdate, OrderResponse, OrderDetailResponse,
    OrderitemCreate, OrderitemUpdate, OrderitemResponse,
    PaymentCreate, PaymentUpdate, PaymentResponse,
    ShipmentCreate, ShipmentUpdate, ShipmentResponse,
    OrderStatus, PaymentStatus, ShipmentStatus
)

router = APIRouter(prefix="/orders", tags=["Orders"])


# Order routes
@router.post(
    "/",
    response_model=OrderResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Order",
    description="Creates a new order record. Validates that buyer, seller, and addresses exist. Returns 409 if order number already exists. Returns 404 if any referenced entity is not found.",
)
def create_order_route(data: OrderCreate, db: Session = Depends(get_db)):
    return handler.create_order(db, data)


@router.get(
    "/",
    response_model=List[OrderResponse],
    summary="List Orders",
    description="Returns a paginated list of orders. Supports optional filters for buyer_id, seller_id, status, and order_number.",
)
def list_orders_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    buyer_id: Optional[str] = None,
    seller_id: Optional[str] = None,
    status: Optional[OrderStatus] = None,
    order_number: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_orders(db, limit, offset, buyer_id, seller_id, status, order_number)


@router.get(
    "/{order_id}",
    response_model=OrderResponse,
    summary="Get Order",
    description="Returns a single order by ID. Returns 404 if order not found.",
)
def get_order_route(order_id: str, db: Session = Depends(get_db)):
    return handler.get_order(db, order_id)


@router.get(
    "/{order_id}/details",
    response_model=OrderDetailResponse,
    summary="Get Order Details",
    description="Returns detailed order information including buyer, seller, order items with listing and card details, payment status, shipment tracking, and addresses. Uses eager loading to prevent N+1 queries. Returns 404 if order not found.",
)
def get_order_details_route(order_id: str, db: Session = Depends(get_db)):
    return handler.get_order_details(db, order_id)


@router.put(
    "/{order_id}",
    response_model=OrderResponse,
    summary="Update Order",
    description="Updates an existing order. Validates that any updated buyer, seller, or addresses exist. Returns 404 if order or referenced entity not found. Returns 409 if updated order number conflicts with existing order.",
)
def update_order_route(order_id: str, data: OrderUpdate, db: Session = Depends(get_db)):
    return handler.update_order(db, order_id, data)


@router.delete(
    "/{order_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Order",
    description="Deletes an order and all related order items, payment, and shipment records via cascade. Returns 404 if order not found.",
)
def delete_order_route(order_id: str, db: Session = Depends(get_db)):
    return handler.delete_order(db, order_id)


@router.post(
    "/{order_id}/ship",
    response_model=OrderResponse,
    summary="Ship Order",
    description="Marks an order as shipped and updates shipment status to IN_TRANSIT. Order must be in PROCESSING status. Returns 400 if order is not in correct status or shipment record not found. Returns 404 if order not found.",
)
def ship_order_route(order_id: str, db: Session = Depends(get_db)):
    return handler.ship_order(db, order_id)


@router.post(
    "/{order_id}/cancel",
    response_model=OrderResponse,
    summary="Cancel Order",
    description="Cancels an order with a reason. Cannot cancel orders after shipment or orders already cancelled/refunded. Returns 400 if order cannot be cancelled. Returns 404 if order not found.",
)
def cancel_order_route(
    order_id: str,
    cancellation_reason: str = Query(..., min_length=1),
    db: Session = Depends(get_db)
):
    return handler.cancel_order(db, order_id, cancellation_reason)


@router.post(
    "/{order_id}/confirm-delivery",
    response_model=OrderResponse,
    summary="Confirm Order Delivery",
    description="Confirms order delivery and updates order status to DELIVERED and shipment status to DELIVERED. Order must be in SHIPPED status. Returns 400 if order is not in correct status or shipment record not found. Returns 404 if order not found.",
)
def confirm_delivery_route(order_id: str, db: Session = Depends(get_db)):
    return handler.confirm_delivery(db, order_id)


@router.get(
    "/{order_id}/tracking",
    summary="Get Order Tracking",
    description="Returns tracking information for an order including carrier, tracking number, shipment status, and delivery dates. Returns 404 if order or shipment not found.",
)
def get_order_tracking_route(order_id: str, db: Session = Depends(get_db)):
    return handler.get_order_tracking(db, order_id)


# Order item routes
@router.post(
    "/items",
    response_model=OrderitemResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Order Item",
    description="Creates a new order item record. Validates that order, listing, and card exist. Returns 404 if any referenced entity not found.",
)
def create_orderitem_route(data: OrderitemCreate, db: Session = Depends(get_db)):
    return handler.create_orderitem(db, data)


@router.get(
    "/items",
    response_model=List[OrderitemResponse],
    summary="List Order Items",
    description="Returns a paginated list of order items. Supports optional filters for order_id, listing_id, and card_id.",
)
def list_orderitems_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    order_id: Optional[str] = None,
    listing_id: Optional[str] = None,
    card_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_orderitems(db, limit, offset, order_id, listing_id, card_id)


@router.get(
    "/items/{orderitem_id}",
    response_model=OrderitemResponse,
    summary="Get Order Item",
    description="Returns a single order item by ID. Returns 404 if order item not found.",
)
def get_orderitem_route(orderitem_id: str, db: Session = Depends(get_db)):
    return handler.get_orderitem(db, orderitem_id)


@router.put(
    "/items/{orderitem_id}",
    response_model=OrderitemResponse,
    summary="Update Order Item",
    description="Updates an existing order item. Validates that any updated order, listing, or card exists. Returns 404 if order item or referenced entity not found.",
)
def update_orderitem_route(orderitem_id: str, data: OrderitemUpdate, db: Session = Depends(get_db)):
    return handler.update_orderitem(db, orderitem_id, data)


@router.delete(
    "/items/{orderitem_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Order Item",
    description="Deletes an order item. Returns 404 if order item not found.",
)
def delete_orderitem_route(orderitem_id: str, db: Session = Depends(get_db)):
    return handler.delete_orderitem(db, orderitem_id)


# Payment routes
@router.post(
    "/payments",
    response_model=PaymentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Payment",
    description="Creates a new payment record for an order. Validates that order exists and payment amount matches order total. Returns 409 if payment already exists for the order. Returns 400 if payment amount does not match order total. Returns 404 if order not found.",
)
def create_payment_route(data: PaymentCreate, db: Session = Depends(get_db)):
    return handler.create_payment(db, data)


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


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


@router.put(
    "/payments/{payment_id}",
    response_model=PaymentResponse,
    summary="Update Payment",
    description="Updates an existing payment. Validates that any updated order exists and no duplicate payment exists for the order. Returns 404 if payment or order not found. Returns 409 if another payment exists for the updated order.",
)
def update_payment_route(payment_id: str, data: PaymentUpdate, db: Session = Depends(get_db)):
    return handler.update_payment(db, payment_id, data)


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


# Shipment routes
@router.post(
    "/shipments",
    response_model=ShipmentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Shipment",
    description="Creates a new shipment record for an order. Validates that order exists. Returns 409 if shipment already exists for the order. Returns 404 if order not found.",
)
def create_shipment_route(data: ShipmentCreate, db: Session = Depends(get_db)):
    return handler.create_shipment(db, data)


@router.get(
    "/shipments",
    response_model=List[ShipmentResponse],
    summary="List Shipments",
    description="Returns a paginated list of shipments. Supports optional filters for order_id, status, carrier, and tracking_number.",
)
def list_shipments_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    order_id: Optional[str] = None,
    status: Optional[ShipmentStatus] = None,
    carrier: Optional[str] = None,
    tracking_number: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_shipments(db, limit, offset, order_id, status, carrier, tracking_number)


@router.get(
    "/shipments/{shipment_id}",
    response_model=ShipmentResponse,
    summary="Get Shipment",
    description="Returns a single shipment by ID. Returns 404 if shipment not found.",
)
def get_shipment_route(shipment_id: str, db: Session = Depends(get_db)):
    return handler.get_shipment(db, shipment_id)


@router.put(
    "/shipments/{shipment_id}",
    response_model=ShipmentResponse,
    summary="Update Shipment",
    description="Updates an existing shipment. Validates that any updated order exists and no duplicate shipment exists for the order. Returns 404 if shipment or order not found. Returns 409 if another shipment exists for the updated order.",
)
def update_shipment_route(shipment_id: str, data: ShipmentUpdate, db: Session = Depends(get_db)):
    return handler.update_shipment(db, shipment_id, data)


@router.delete(
    "/shipments/{shipment_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Shipment",
    description="Deletes a shipment record. Returns 404 if shipment not found.",
)
def delete_shipment_route(shipment_id: str, db: Session = Depends(get_db)):
    return handler.delete_shipment(db, shipment_id)