# services/suppliers/app/api/deliveries.py
"""
Delivery 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.delivery_service import DeliveryService
from app.schemas.suppliers import (
    DeliveryCreate, DeliveryUpdate, DeliveryResponse, DeliverySummary,
    DeliverySearchParams, DeliveryStatusUpdate, DeliveryReceiptConfirmation,
    DeliveryPerformanceStats, DeliverySummaryStats
)
from app.models.suppliers import DeliveryStatus
from shared.auth.decorators import get_current_user_dep
from typing import Dict, Any

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


@router.post("/", response_model=DeliveryResponse)
async def create_delivery(
    delivery_data: DeliveryCreate,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Create a new delivery"""
    # require_permissions(current_user, ["deliveries:create"])
    
    try:
        service = DeliveryService(db)
        delivery = await service.create_delivery(
            tenant_id=current_user.tenant_id,
            delivery_data=delivery_data,
            created_by=current_user.user_id
        )
        return DeliveryResponse.from_orm(delivery)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error creating delivery", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to create delivery")


@router.get("/", response_model=List[DeliverySummary])
async def list_deliveries(
    supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
    status: Optional[str] = Query(None, description="Filter by status"),
    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 deliveries with optional filters"""
    # require_permissions(current_user, ["deliveries: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 = DeliveryStatus(status.upper())
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid status")
        
        service = DeliveryService(db)
        search_params = DeliverySearchParams(
            supplier_id=supplier_id,
            status=status_enum,
            date_from=date_from_parsed,
            date_to=date_to_parsed,
            search_term=search_term,
            limit=limit,
            offset=offset
        )
        
        deliveries = await service.search_deliveries(
            tenant_id=current_user.tenant_id,
            search_params=search_params
        )
        
        return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error listing deliveries", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve deliveries")


@router.get("/today", response_model=List[DeliverySummary])
async def get_todays_deliveries(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get deliveries scheduled for today"""
    # require_permissions(current_user, ["deliveries:read"])
    
    try:
        service = DeliveryService(db)
        deliveries = await service.get_todays_deliveries(current_user.tenant_id)
        return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
    except Exception as e:
        logger.error("Error getting today's deliveries", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve today's deliveries")


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


@router.get("/scheduled", response_model=List[DeliverySummary])
async def get_scheduled_deliveries(
    date_from: Optional[str] = Query(None, description="From date (YYYY-MM-DD)"),
    date_to: Optional[str] = Query(None, description="To date (YYYY-MM-DD)"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get scheduled deliveries for a date range"""
    # require_permissions(current_user, ["deliveries:read"])
    
    try:
        from datetime import datetime
        
        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")
        
        service = DeliveryService(db)
        deliveries = await service.get_scheduled_deliveries(
            tenant_id=current_user.tenant_id,
            date_from=date_from_parsed,
            date_to=date_to_parsed
        )
        return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting scheduled deliveries", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve scheduled deliveries")


@router.get("/performance-stats", response_model=DeliveryPerformanceStats)
async def get_delivery_performance_stats(
    days_back: int = Query(30, ge=1, le=365, description="Number of days to analyze"),
    supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get delivery performance statistics"""
    # require_permissions(current_user, ["deliveries:read"])
    
    try:
        service = DeliveryService(db)
        stats = await service.get_delivery_performance_stats(
            tenant_id=current_user.tenant_id,
            days_back=days_back,
            supplier_id=supplier_id
        )
        return DeliveryPerformanceStats(**stats)
    except Exception as e:
        logger.error("Error getting delivery performance stats", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve delivery performance statistics")


@router.get("/summary-stats", response_model=DeliverySummaryStats)
async def get_delivery_summary_stats(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get delivery summary statistics for dashboard"""
    # require_permissions(current_user, ["deliveries:read"])
    
    try:
        service = DeliveryService(db)
        stats = await service.get_upcoming_deliveries_summary(current_user.tenant_id)
        return DeliverySummaryStats(**stats)
    except Exception as e:
        logger.error("Error getting delivery summary stats", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve delivery summary statistics")


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


@router.put("/{delivery_id}", response_model=DeliveryResponse)
async def update_delivery(
    delivery_data: DeliveryUpdate,
    delivery_id: UUID = Path(..., description="Delivery ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Update delivery information"""
    # require_permissions(current_user, ["deliveries:update"])
    
    try:
        service = DeliveryService(db)
        
        # Check delivery exists and belongs to tenant
        existing_delivery = await service.get_delivery(delivery_id)
        if not existing_delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        if existing_delivery.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        delivery = await service.update_delivery(
            delivery_id=delivery_id,
            delivery_data=delivery_data,
            updated_by=current_user.user_id
        )
        
        if not delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        
        return DeliveryResponse.from_orm(delivery)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating delivery", delivery_id=str(delivery_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to update delivery")


@router.patch("/{delivery_id}/status", response_model=DeliveryResponse)
async def update_delivery_status(
    status_data: DeliveryStatusUpdate,
    delivery_id: UUID = Path(..., description="Delivery ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Update delivery status"""
    # require_permissions(current_user, ["deliveries:update"])
    
    try:
        service = DeliveryService(db)
        
        # Check delivery exists and belongs to tenant
        existing_delivery = await service.get_delivery(delivery_id)
        if not existing_delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        if existing_delivery.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        delivery = await service.update_delivery_status(
            delivery_id=delivery_id,
            status=status_data.status,
            updated_by=current_user.user_id,
            notes=status_data.notes,
            update_timestamps=status_data.update_timestamps
        )
        
        if not delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        
        return DeliveryResponse.from_orm(delivery)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating delivery status", delivery_id=str(delivery_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to update delivery status")


@router.post("/{delivery_id}/receive", response_model=DeliveryResponse)
async def receive_delivery(
    receipt_data: DeliveryReceiptConfirmation,
    delivery_id: UUID = Path(..., description="Delivery ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Mark delivery as received with inspection details"""
    # require_permissions(current_user, ["deliveries:receive"])
    
    try:
        service = DeliveryService(db)
        
        # Check delivery exists and belongs to tenant
        existing_delivery = await service.get_delivery(delivery_id)
        if not existing_delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        if existing_delivery.tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        delivery = await service.mark_as_received(
            delivery_id=delivery_id,
            received_by=current_user.user_id,
            inspection_passed=receipt_data.inspection_passed,
            inspection_notes=receipt_data.inspection_notes,
            quality_issues=receipt_data.quality_issues,
            notes=receipt_data.notes
        )
        
        if not delivery:
            raise HTTPException(status_code=404, detail="Delivery not found")
        
        return DeliveryResponse.from_orm(delivery)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error receiving delivery", delivery_id=str(delivery_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to receive delivery")


@router.get("/purchase-order/{po_id}", response_model=List[DeliverySummary])
async def get_deliveries_by_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 all deliveries for a purchase order"""
    # require_permissions(current_user, ["deliveries:read"])
    
    try:
        service = DeliveryService(db)
        deliveries = await service.get_deliveries_by_purchase_order(po_id)
        
        # Check tenant access for first delivery (all should belong to same tenant)
        if deliveries and deliveries[0].tenant_id != current_user.tenant_id:
            raise HTTPException(status_code=403, detail="Access denied")
        
        return [DeliverySummary.from_orm(delivery) for delivery in deliveries]
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting deliveries by purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve deliveries for purchase order")