"""
Expected Deliveries API for Procurement Service
Public endpoint for expected delivery tracking
"""

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload
import structlog
import uuid
from datetime import datetime, timezone, timedelta
from typing import Optional, List
from decimal import Decimal

from app.core.database import get_db
from app.models.purchase_order import PurchaseOrder, PurchaseOrderItem, PurchaseOrderStatus
from shared.auth.decorators import get_current_user_dep
from shared.routing import RouteBuilder

logger = structlog.get_logger()
route_builder = RouteBuilder('procurement')
router = APIRouter(tags=["expected-deliveries"])


@router.get(
    route_builder.build_base_route("expected-deliveries")
)
async def get_expected_deliveries(
    tenant_id: str,
    days_ahead: int = Query(1, description="Number of days to look ahead", ge=0, le=30),
    include_overdue: bool = Query(True, description="Include overdue deliveries"),
    current_user: dict = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Get expected deliveries for delivery tracking system.

    Args:
        tenant_id: Tenant UUID to query
        days_ahead: Number of days to look ahead (default 1 = today + tomorrow)
        include_overdue: Include deliveries past expected date (default True)

    Returns:
        {
            "deliveries": [
                {
                    "po_id": "uuid",
                    "po_number": "PO-2025-123",
                    "supplier_id": "uuid",
                    "supplier_name": "Molinos San José",
                    "supplier_phone": "+34 915 234 567",
                    "expected_delivery_date": "2025-12-02T10:00:00Z",
                    "delivery_window_hours": 4,
                    "status": "sent_to_supplier",
                    "line_items": [...],
                    "total_amount": 540.00,
                    "currency": "EUR"
                }
            ],
            "total_count": 8
        }
    """
    try:
        # Parse tenant_id
        tenant_uuid = uuid.UUID(tenant_id)

        # Calculate date range
        now = datetime.now(timezone.utc)
        end_date = now + timedelta(days=days_ahead)

        logger.info(
            "Fetching expected deliveries",
            tenant_id=tenant_id,
            days_ahead=days_ahead,
            include_overdue=include_overdue
        )

        # Build query for purchase orders with expected delivery dates
        query = select(PurchaseOrder).options(
            selectinload(PurchaseOrder.items)
        ).where(
            PurchaseOrder.tenant_id == tenant_uuid,
            PurchaseOrder.expected_delivery_date.isnot(None),
            PurchaseOrder.status.in_([
                PurchaseOrderStatus.approved,
                PurchaseOrderStatus.sent_to_supplier,
                PurchaseOrderStatus.confirmed
            ])
        )

        # Add date filters
        if include_overdue:
            # Include deliveries from last 48 hours (recent overdue) until end_date
            # This ensures we only show truly recent overdue deliveries, not ancient history
            start_date = now - timedelta(hours=48)
            query = query.where(
                PurchaseOrder.expected_delivery_date >= start_date,
                PurchaseOrder.expected_delivery_date <= end_date
            )
        else:
            # Only future deliveries within range
            query = query.where(
                PurchaseOrder.expected_delivery_date >= now,
                PurchaseOrder.expected_delivery_date <= end_date
            )

        # Order by delivery date
        query = query.order_by(PurchaseOrder.expected_delivery_date.asc())

        # Execute query
        result = await db.execute(query)
        purchase_orders = result.scalars().all()

        # Format deliveries for response
        deliveries = []

        for po in purchase_orders:
            # Get supplier info from supplier service (for now, use supplier_id)
            # In production, you'd fetch from supplier service or join if same DB
            supplier_name = f"Supplier-{str(po.supplier_id)[:8]}"
            supplier_phone = None

            # Try to get supplier details from notes or metadata
            # This is a simplified approach - in production you'd query supplier service
            if po.notes:
                if "Molinos San José" in po.notes:
                    supplier_name = "Molinos San José S.L."
                    supplier_phone = "+34 915 234 567"
                elif "Lácteos del Valle" in po.notes:
                    supplier_name = "Lácteos del Valle S.A."
                    supplier_phone = "+34 913 456 789"
                elif "Chocolates Valor" in po.notes:
                    supplier_name = "Chocolates Valor"
                    supplier_phone = "+34 965 510 062"
                elif "Suministros Hostelería" in po.notes:
                    supplier_name = "Suministros Hostelería"
                    supplier_phone = "+34 911 234 567"
                elif "Miel Artesana" in po.notes:
                    supplier_name = "Miel Artesana"
                    supplier_phone = "+34 918 765 432"

            # Format line items (limit to first 5)
            line_items = []
            for item in po.items[:5]:
                line_items.append({
                    "product_name": item.product_name,
                    "quantity": float(item.ordered_quantity) if item.ordered_quantity else 0,
                    "unit": item.unit_of_measure or "unit"
                })

            # Default delivery window is 4 hours
            delivery_window_hours = 4

            # Ensure expected delivery date is timezone-aware and in UTC format
            expected_delivery_utc = po.expected_delivery_date
            if expected_delivery_utc and expected_delivery_utc.tzinfo is None:
                # If naive datetime, assume it's UTC (this shouldn't happen with proper DB setup)
                expected_delivery_utc = expected_delivery_utc.replace(tzinfo=timezone.utc)
            elif expected_delivery_utc and expected_delivery_utc.tzinfo is not None:
                # Convert to UTC if it's in another timezone
                expected_delivery_utc = expected_delivery_utc.astimezone(timezone.utc)

            delivery_dict = {
                "po_id": str(po.id),
                "po_number": po.po_number,
                "supplier_id": str(po.supplier_id),
                "supplier_name": supplier_name,
                "supplier_phone": supplier_phone,
                "expected_delivery_date": expected_delivery_utc.isoformat() if expected_delivery_utc else None,
                "delivery_window_hours": delivery_window_hours,
                "status": po.status.value,
                "line_items": line_items,
                "total_amount": float(po.total_amount) if po.total_amount else 0.0,
                "currency": po.currency
            }

            deliveries.append(delivery_dict)

        logger.info(
            "Expected deliveries retrieved",
            tenant_id=tenant_id,
            count=len(deliveries)
        )

        return {
            "deliveries": deliveries,
            "total_count": len(deliveries)
        }

    except ValueError as e:
        logger.error("Invalid UUID format", error=str(e), tenant_id=tenant_id)
        raise HTTPException(status_code=400, detail=f"Invalid UUID: {tenant_id}")

    except Exception as e:
        logger.error(
            "Error fetching expected deliveries",
            error=str(e),
            tenant_id=tenant_id,
            exc_info=True
        )
        raise HTTPException(status_code=500, detail="Internal server error")
