# ================================================================
# services/orders/app/api/orders.py
# ================================================================
"""
Orders API endpoints for Orders Service
"""

from datetime import date, datetime
from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Path, Query, status
from fastapi.responses import JSONResponse
import structlog

from shared.auth.decorators import get_current_user_dep
from app.core.database import get_db
from app.services.orders_service import OrdersService
from app.schemas.order_schemas import (
    OrderCreate,
    OrderUpdate,
    OrderResponse,
    CustomerCreate,
    CustomerUpdate,
    CustomerResponse,
    OrdersDashboardSummary,
    DemandRequirements,
    ProcurementPlanningData
)

logger = structlog.get_logger()

router = APIRouter()


# ===== Dependency Injection =====

async def get_orders_service(db = Depends(get_db)) -> OrdersService:
    """Get orders service with dependencies"""
    from app.repositories.order_repository import (
        OrderRepository,
        CustomerRepository,
        OrderItemRepository,
        OrderStatusHistoryRepository
    )
    from shared.clients import (
        get_inventory_client,
        get_production_client,
        get_sales_client
    )
    
    return OrdersService(
        order_repo=OrderRepository(),
        customer_repo=CustomerRepository(),
        order_item_repo=OrderItemRepository(),
        status_history_repo=OrderStatusHistoryRepository(),
        inventory_client=get_inventory_client(),
        production_client=get_production_client(),
        sales_client=get_sales_client()
    )


# ===== Dashboard and Analytics Endpoints =====

@router.get("/tenants/{tenant_id}/orders/dashboard-summary", response_model=OrdersDashboardSummary)
async def get_dashboard_summary(
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get comprehensive dashboard summary for orders"""
    try:
        summary = await orders_service.get_dashboard_summary(db, tenant_id)
        
        logger.info("Dashboard summary retrieved", 
                   tenant_id=str(tenant_id),
                   total_orders=summary.total_orders_today)
        
        return summary
        
    except Exception as e:
        logger.error("Error getting dashboard summary", 
                    tenant_id=str(tenant_id), 
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve dashboard summary"
        )


@router.get("/tenants/{tenant_id}/orders/demand-requirements", response_model=DemandRequirements)
async def get_demand_requirements(
    tenant_id: UUID = Path(...),
    target_date: date = Query(..., description="Date for demand analysis"),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get demand requirements for production planning"""
    try:
        requirements = await orders_service.get_demand_requirements(db, tenant_id, target_date)
        
        logger.info("Demand requirements calculated", 
                   tenant_id=str(tenant_id),
                   target_date=str(target_date),
                   total_orders=requirements.total_orders)
        
        return requirements
        
    except Exception as e:
        logger.error("Error getting demand requirements", 
                    tenant_id=str(tenant_id), 
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to calculate demand requirements"
        )


# ===== Order Management Endpoints =====

@router.post("/tenants/{tenant_id}/orders", response_model=OrderResponse, status_code=status.HTTP_201_CREATED)
async def create_order(
    order_data: OrderCreate,
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Create a new customer order"""
    try:
        # Ensure tenant_id matches
        order_data.tenant_id = tenant_id
        
        order = await orders_service.create_order(
            db, 
            order_data, 
            user_id=UUID(current_user["sub"])
        )
        
        logger.info("Order created successfully", 
                   order_id=str(order.id),
                   order_number=order.order_number)
        
        return order
        
    except ValueError as e:
        logger.warning("Invalid order data", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        logger.error("Error creating order", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create order"
        )


@router.get("/tenants/{tenant_id}/orders/{order_id}", response_model=OrderResponse)
async def get_order(
    tenant_id: UUID = Path(...),
    order_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get order details with items"""
    try:
        order = await orders_service.get_order_with_items(db, order_id, tenant_id)
        if not order:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Order not found"
            )
        
        return order
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting order", 
                    order_id=str(order_id), 
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve order"
        )


@router.get("/tenants/{tenant_id}/orders", response_model=List[OrderResponse])
async def get_orders(
    tenant_id: UUID = Path(...),
    status_filter: Optional[str] = Query(None, description="Filter by order status"),
    start_date: Optional[date] = Query(None, description="Start date for date range filter"),
    end_date: Optional[date] = Query(None, description="End date for date range filter"),
    skip: int = Query(0, ge=0, description="Number of orders to skip"),
    limit: int = Query(100, ge=1, le=1000, description="Number of orders to return"),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get orders with filtering and pagination"""
    try:
        # Determine which repository method to use based on filters
        if status_filter:
            orders = await orders_service.order_repo.get_orders_by_status(
                db, tenant_id, status_filter, skip, limit
            )
        elif start_date and end_date:
            orders = await orders_service.order_repo.get_orders_by_date_range(
                db, tenant_id, start_date, end_date, skip, limit
            )
        else:
            orders = await orders_service.order_repo.get_multi(
                db, tenant_id, skip, limit, order_by="order_date", order_desc=True
            )
        
        return [OrderResponse.from_orm(order) for order in orders]
        
    except Exception as e:
        logger.error("Error getting orders", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve orders"
        )


@router.put("/tenants/{tenant_id}/orders/{order_id}/status", response_model=OrderResponse)
async def update_order_status(
    new_status: str,
    tenant_id: UUID = Path(...),
    order_id: UUID = Path(...),
    reason: Optional[str] = Query(None, description="Reason for status change"),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Update order status"""
    try:
        # Validate status
        valid_statuses = ["pending", "confirmed", "in_production", "ready", "out_for_delivery", "delivered", "cancelled", "failed"]
        if new_status not in valid_statuses:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid status. Must be one of: {', '.join(valid_statuses)}"
            )
        
        order = await orders_service.update_order_status(
            db, 
            order_id, 
            tenant_id, 
            new_status,
            user_id=UUID(current_user["sub"]),
            reason=reason
        )
        
        if not order:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Order not found"
            )
        
        logger.info("Order status updated", 
                   order_id=str(order_id),
                   new_status=new_status)
        
        return order
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error updating order status", 
                    order_id=str(order_id), 
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to update order status"
        )


# ===== Customer Management Endpoints =====

@router.post("/tenants/{tenant_id}/customers", response_model=CustomerResponse, status_code=status.HTTP_201_CREATED)
async def create_customer(
    customer_data: CustomerCreate,
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Create a new customer"""
    try:
        # Ensure tenant_id matches
        customer_data.tenant_id = tenant_id
        
        # Check if customer code already exists
        existing_customer = await orders_service.customer_repo.get_by_customer_code(
            db, customer_data.customer_code, tenant_id
        )
        if existing_customer:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Customer code already exists"
            )
        
        customer = await orders_service.customer_repo.create(
            db, 
            obj_in=customer_data.dict(),
            created_by=UUID(current_user["sub"])
        )
        
        logger.info("Customer created successfully", 
                   customer_id=str(customer.id),
                   customer_code=customer.customer_code)
        
        return CustomerResponse.from_orm(customer)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error creating customer", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create customer"
        )


@router.get("/tenants/{tenant_id}/customers", response_model=List[CustomerResponse])
async def get_customers(
    tenant_id: UUID = Path(...),
    active_only: bool = Query(True, description="Filter for active customers only"),
    skip: int = Query(0, ge=0, description="Number of customers to skip"),
    limit: int = Query(100, ge=1, le=1000, description="Number of customers to return"),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get customers with filtering and pagination"""
    try:
        if active_only:
            customers = await orders_service.customer_repo.get_active_customers(
                db, tenant_id, skip, limit
            )
        else:
            customers = await orders_service.customer_repo.get_multi(
                db, tenant_id, skip, limit, order_by="name"
            )
        
        return [CustomerResponse.from_orm(customer) for customer in customers]
        
    except Exception as e:
        logger.error("Error getting customers", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve customers"
        )


@router.get("/tenants/{tenant_id}/customers/{customer_id}", response_model=CustomerResponse)
async def get_customer(
    tenant_id: UUID = Path(...),
    customer_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Get customer details"""
    try:
        customer = await orders_service.customer_repo.get(db, customer_id, tenant_id)
        if not customer:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Customer not found"
            )
        
        return CustomerResponse.from_orm(customer)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting customer", 
                    customer_id=str(customer_id), 
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve customer"
        )


# ===== Business Intelligence Endpoints =====

@router.get("/tenants/{tenant_id}/orders/business-model")
async def detect_business_model(
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    orders_service: OrdersService = Depends(get_orders_service),
    db = Depends(get_db)
):
    """Detect business model based on order patterns"""
    try:
        business_model = await orders_service.detect_business_model(db, tenant_id)
        
        return {
            "business_model": business_model,
            "confidence": "high" if business_model else "unknown",
            "detected_at": datetime.now().isoformat()
        }
        
    except Exception as e:
        logger.error("Error detecting business model", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to detect business model"
        )


# ===== Health and Status Endpoints =====

@router.get("/tenants/{tenant_id}/orders/status")
async def get_service_status(
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep)
):
    """Get orders service status"""
    try:
        return {
            "service": "orders-service",
            "status": "healthy",
            "timestamp": datetime.now().isoformat(),
            "tenant_id": str(tenant_id)
        }
        
    except Exception as e:
        logger.error("Error getting service status", error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to get service status"
        )