# services/suppliers/app/api/purchase_orders.py
"""
Purchase Order API endpoints
"""

from fastapi import APIRouter, Depends, HTTPException, Query, Path
from typing import List, Optional
from uuid import UUID
import structlog

from sqlalchemy.orm import Session
from app.core.database import get_db
from app.services.purchase_order_service import PurchaseOrderService
from app.schemas.suppliers import (
    PurchaseOrderCreate, PurchaseOrderUpdate, PurchaseOrderResponse, PurchaseOrderSummary,
    PurchaseOrderSearchParams, PurchaseOrderStatusUpdate, PurchaseOrderApproval,
    PurchaseOrderStatistics
)
from app.models.suppliers import PurchaseOrderStatus
from shared.auth.decorators import get_current_user_dep
from typing import Dict, Any

router = APIRouter(prefix="/purchase-orders", tags=["purchase-orders"])
logger = structlog.get_logger()


@router.post("/", response_model=PurchaseOrderResponse)
async def create_purchase_order(
    po_data: PurchaseOrderCreate,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Create a new purchase order"""
    # require_permissions(current_user, ["purchase_orders:create"])
    
    try:
        service = PurchaseOrderService(db)
        purchase_order = await service.create_purchase_order(
            tenant_id=current_user.tenant_id,
            po_data=po_data,
            created_by=current_user.user_id
        )
        return PurchaseOrderResponse.from_orm(purchase_order)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error creating purchase order", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to create purchase order")


@router.get("/", response_model=List[PurchaseOrderSummary])
async def list_purchase_orders(
    supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
    status: Optional[str] = Query(None, description="Filter by status"),
    priority: Optional[str] = Query(None, description="Filter by priority"),
    date_from: Optional[str] = Query(None, description="Filter from date (YYYY-MM-DD)"),
    date_to: Optional[str] = Query(None, description="Filter to date (YYYY-MM-DD)"),
    search_term: Optional[str] = Query(None, description="Search term"),
    limit: int = Query(50, ge=1, le=1000, description="Number of results to return"),
    offset: int = Query(0, ge=0, description="Number of results to skip"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """List purchase orders with optional filters"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        from datetime import datetime
        
        # Parse date filters
        date_from_parsed = None
        date_to_parsed = None
        if date_from:
            try:
                date_from_parsed = datetime.fromisoformat(date_from)
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid date_from format")
        
        if date_to:
            try:
                date_to_parsed = datetime.fromisoformat(date_to)
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid date_to format")
        
        # Validate status
        status_enum = None
        if status:
            try:
                status_enum = PurchaseOrderStatus(status.upper())
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid status")
        
        service = PurchaseOrderService(db)
        search_params = PurchaseOrderSearchParams(
            supplier_id=supplier_id,
            status=status_enum,
            priority=priority,
            date_from=date_from_parsed,
            date_to=date_to_parsed,
            search_term=search_term,
            limit=limit,
            offset=offset
        )
        
        orders = await service.search_purchase_orders(
            tenant_id=current_user.tenant_id,
            search_params=search_params
        )
        
        return [PurchaseOrderSummary.from_orm(order) for order in orders]
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error listing purchase orders", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve purchase orders")


@router.get("/statistics", response_model=PurchaseOrderStatistics)
async def get_purchase_order_statistics(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get purchase order statistics for dashboard"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        stats = await service.get_purchase_order_statistics(current_user.tenant_id)
        return PurchaseOrderStatistics(**stats)
    except Exception as e:
        logger.error("Error getting purchase order statistics", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve statistics")


@router.get("/pending-approval", response_model=List[PurchaseOrderSummary])
async def get_orders_requiring_approval(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get purchase orders requiring approval"""
    # require_permissions(current_user, ["purchase_orders:approve"])
    
    try:
        service = PurchaseOrderService(db)
        orders = await service.get_orders_requiring_approval(current_user.tenant_id)
        return [PurchaseOrderSummary.from_orm(order) for order in orders]
    except Exception as e:
        logger.error("Error getting orders requiring approval", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve orders requiring approval")


@router.get("/overdue", response_model=List[PurchaseOrderSummary])
async def get_overdue_orders(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get overdue purchase orders"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        orders = await service.get_overdue_orders(current_user.tenant_id)
        return [PurchaseOrderSummary.from_orm(order) for order in orders]
    except Exception as e:
        logger.error("Error getting overdue orders", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve overdue orders")


@router.get("/{po_id}", response_model=PurchaseOrderResponse)
async def get_purchase_order(
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get purchase order by ID with items"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        purchase_order = await service.get_purchase_order(po_id)
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        # Check tenant access
        if purchase_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve purchase order")


@router.put("/{po_id}", response_model=PurchaseOrderResponse)
async def update_purchase_order(
    po_data: PurchaseOrderUpdate,
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Update purchase order information"""
    # require_permissions(current_user, ["purchase_orders:update"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        purchase_order = await service.update_purchase_order(
            po_id=po_id,
            po_data=po_data,
            updated_by=current_user.user_id
        )
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to update purchase order")


@router.patch("/{po_id}/status", response_model=PurchaseOrderResponse)
async def update_purchase_order_status(
    status_data: PurchaseOrderStatusUpdate,
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Update purchase order status"""
    # require_permissions(current_user, ["purchase_orders:update"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        purchase_order = await service.update_order_status(
            po_id=po_id,
            status=status_data.status,
            updated_by=current_user.user_id,
            notes=status_data.notes
        )
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating purchase order status", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to update purchase order status")


@router.post("/{po_id}/approve", response_model=PurchaseOrderResponse)
async def approve_purchase_order(
    approval_data: PurchaseOrderApproval,
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Approve or reject a purchase order"""
    # require_permissions(current_user, ["purchase_orders:approve"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        if approval_data.action == "approve":
            purchase_order = await service.approve_purchase_order(
                po_id=po_id,
                approved_by=current_user.user_id,
                approval_notes=approval_data.notes
            )
        elif approval_data.action == "reject":
            if not approval_data.notes:
                raise HTTPException(status_code=400, detail="Rejection reason is required")
            purchase_order = await service.reject_purchase_order(
                po_id=po_id,
                rejection_reason=approval_data.notes,
                rejected_by=current_user.user_id
            )
        else:
            raise HTTPException(status_code=400, detail="Invalid action")
        
        if not purchase_order:
            raise HTTPException(
                status_code=400, 
                detail="Purchase order is not in pending approval status"
            )
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error processing purchase order approval", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to process purchase order approval")


@router.post("/{po_id}/send-to-supplier", response_model=PurchaseOrderResponse)
async def send_to_supplier(
    po_id: UUID = Path(..., description="Purchase order ID"),
    send_email: bool = Query(True, description="Send email notification to supplier"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Send purchase order to supplier"""
    # require_permissions(current_user, ["purchase_orders:send"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        purchase_order = await service.send_to_supplier(
            po_id=po_id,
            sent_by=current_user.user_id,
            send_email=send_email
        )
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error sending purchase order to supplier", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to send purchase order to supplier")


@router.post("/{po_id}/confirm-supplier-receipt", response_model=PurchaseOrderResponse)
async def confirm_supplier_receipt(
    po_id: UUID = Path(..., description="Purchase order ID"),
    supplier_reference: Optional[str] = Query(None, description="Supplier's order reference"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Confirm supplier has received and accepted the order"""
    # require_permissions(current_user, ["purchase_orders:update"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        purchase_order = await service.confirm_supplier_receipt(
            po_id=po_id,
            supplier_reference=supplier_reference,
            confirmed_by=current_user.user_id
        )
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error confirming supplier receipt", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to confirm supplier receipt")


@router.post("/{po_id}/cancel", response_model=PurchaseOrderResponse)
async def cancel_purchase_order(
    po_id: UUID = Path(..., description="Purchase order ID"),
    cancellation_reason: str = Query(..., description="Reason for cancellation"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Cancel a purchase order"""
    # require_permissions(current_user, ["purchase_orders:cancel"])
    
    try:
        service = PurchaseOrderService(db)
        
        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        purchase_order = await service.cancel_purchase_order(
            po_id=po_id,
            cancellation_reason=cancellation_reason,
            cancelled_by=current_user.user_id
        )
        
        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error cancelling purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to cancel purchase order")


@router.get("/supplier/{supplier_id}", response_model=List[PurchaseOrderSummary])
async def get_orders_by_supplier(
    supplier_id: UUID = Path(..., description="Supplier ID"),
    limit: int = Query(20, ge=1, le=100, description="Number of orders to return"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get recent purchase orders for a specific supplier"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        orders = await service.get_orders_by_supplier(
            tenant_id=current_user.tenant_id,
            supplier_id=supplier_id,
            limit=limit
        )
        return [PurchaseOrderSummary.from_orm(order) for order in orders]
    except Exception as e:
        logger.error("Error getting orders by supplier", supplier_id=str(supplier_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve orders by supplier")


@router.get("/inventory-products/{inventory_product_id}/history")
async def get_inventory_product_purchase_history(
    inventory_product_id: UUID = Path(..., description="Inventory Product ID"),
    days_back: int = Query(90, ge=1, le=365, description="Number of days to look back"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get purchase history for a specific inventory product"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        history = await service.get_inventory_product_purchase_history(
            tenant_id=current_user.tenant_id,
            inventory_product_id=inventory_product_id,
            days_back=days_back
        )
        return history
    except Exception as e:
        logger.error("Error getting inventory product purchase history", inventory_product_id=str(inventory_product_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve inventory product purchase history")


@router.get("/inventory-products/top-purchased")
async def get_top_purchased_inventory_products(
    days_back: int = Query(30, ge=1, le=365, description="Number of days to look back"),
    limit: int = Query(10, ge=1, le=50, description="Number of top inventory products to return"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get most purchased inventory products by value"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        products = await service.get_top_purchased_inventory_products(
            tenant_id=current_user.tenant_id,
            days_back=days_back,
            limit=limit
        )
        return products
    except Exception as e:
        logger.error("Error getting top purchased inventory products", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve top purchased inventory products")