"""
Replenishment Planning API Routes

Provides endpoints for advanced replenishment planning including:
- Generate replenishment plans
- View inventory projections
- Review supplier allocations
- Get planning analytics
"""

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

from app.schemas.replenishment import (
    GenerateReplenishmentPlanRequest,
    GenerateReplenishmentPlanResponse,
    ReplenishmentPlanResponse,
    ReplenishmentPlanSummary,
    InventoryProjectionResponse,
    SupplierAllocationResponse,
    SupplierSelectionRequest,
    SupplierSelectionResult,
    SafetyStockRequest,
    SafetyStockResponse,
    ProjectInventoryRequest,
    ProjectInventoryResponse,
    ReplenishmentAnalytics,
    MOQAggregationRequest,
    MOQAggregationResponse
)
from app.services.procurement_service import ProcurementService
from app.services.replenishment_planning_service import ReplenishmentPlanningService
from app.services.safety_stock_calculator import SafetyStockCalculator
from app.services.inventory_projector import InventoryProjector, DailyDemand, ScheduledReceipt
from app.services.moq_aggregator import MOQAggregator
from app.services.supplier_selector import SupplierSelector
from app.core.dependencies import get_db, get_current_tenant_id
from sqlalchemy.ext.asyncio import AsyncSession
from shared.routing import RouteBuilder
import structlog

logger = structlog.get_logger()

# Create route builder for consistent URL structure
route_builder = RouteBuilder('procurement')
router = APIRouter(tags=["replenishment-planning"])


# ============================================================
# Replenishment Plan Endpoints
# ============================================================

@router.post(
    route_builder.build_operations_route("replenishment-plans/generate"),
    response_model=GenerateReplenishmentPlanResponse
)
async def generate_replenishment_plan(
    request: GenerateReplenishmentPlanRequest,
    tenant_id: UUID = Depends(get_current_tenant_id),
    db: AsyncSession = Depends(get_db)
):
    """
    Generate advanced replenishment plan with:
    - Lead-time-aware order date calculation
    - Dynamic safety stock
    - Inventory projection
    - Shelf-life management
    """
    try:
        logger.info("Generating replenishment plan", tenant_id=tenant_id)

        # Initialize replenishment planner
        planner = ReplenishmentPlanningService(
            projection_horizon_days=request.projection_horizon_days,
            default_service_level=request.service_level,
            default_buffer_days=request.buffer_days
        )

        # Generate plan
        plan = await planner.generate_replenishment_plan(
            tenant_id=str(tenant_id),
            requirements=request.requirements,
            forecast_id=request.forecast_id,
            production_schedule_id=request.production_schedule_id
        )

        # Export to response
        plan_dict = planner.export_plan_to_dict(plan)

        return GenerateReplenishmentPlanResponse(**plan_dict)

    except Exception as e:
        logger.error("Failed to generate replenishment plan",
                    tenant_id=tenant_id, error=str(e), exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_operations_route("replenishment-plans"),
    response_model=List[ReplenishmentPlanSummary]
)
async def list_replenishment_plans(
    tenant_id: UUID = Depends(get_current_tenant_id),
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    status: Optional[str] = None,
    db: AsyncSession = Depends(get_db)
):
    """
    List replenishment plans for tenant
    """
    try:
        # Query from database (implementation depends on your repo)
        # This is a placeholder - implement based on your repository
        from app.repositories.replenishment_repository import ReplenishmentPlanRepository

        repo = ReplenishmentPlanRepository(db)
        plans = await repo.list_plans(
            tenant_id=tenant_id,
            skip=skip,
            limit=limit,
            status=status
        )

        return plans

    except Exception as e:
        logger.error("Failed to list replenishment plans",
                    tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_resource_detail_route("replenishment-plans", "plan_id"),
    response_model=ReplenishmentPlanResponse
)
async def get_replenishment_plan(
    plan_id: UUID = Path(...),
    tenant_id: UUID = Depends(get_current_tenant_id),
    db: AsyncSession = Depends(get_db)
):
    """
    Get replenishment plan by ID
    """
    try:
        from app.repositories.replenishment_repository import ReplenishmentPlanRepository

        repo = ReplenishmentPlanRepository(db)
        plan = await repo.get_plan_by_id(plan_id, tenant_id)

        if not plan:
            raise HTTPException(status_code=404, detail="Replenishment plan not found")

        return plan

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Failed to get replenishment plan",
                    tenant_id=tenant_id, plan_id=plan_id, error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================
# Inventory Projection Endpoints
# ============================================================

@router.post(
    route_builder.build_operations_route("replenishment-plans/inventory-projections/project"),
    response_model=ProjectInventoryResponse
)
async def project_inventory(
    request: ProjectInventoryRequest,
    tenant_id: UUID = Depends(get_current_tenant_id)
):
    """
    Project inventory levels to identify future stockouts
    """
    try:
        logger.info("Projecting inventory", tenant_id=tenant_id,
                   ingredient_id=request.ingredient_id)

        projector = InventoryProjector(request.projection_horizon_days)

        # Build daily demand objects
        daily_demand = [
            DailyDemand(
                ingredient_id=request.ingredient_id,
                date=d['date'],
                quantity=d['quantity']
            )
            for d in request.daily_demand
        ]

        # Build scheduled receipts
        scheduled_receipts = [
            ScheduledReceipt(
                ingredient_id=request.ingredient_id,
                date=r['date'],
                quantity=r['quantity'],
                source=r.get('source', 'purchase_order'),
                reference_id=r.get('reference_id')
            )
            for r in request.scheduled_receipts
        ]

        # Project inventory
        projection = projector.project_inventory(
            ingredient_id=request.ingredient_id,
            ingredient_name=request.ingredient_name,
            current_stock=request.current_stock,
            unit_of_measure=request.unit_of_measure,
            daily_demand=daily_demand,
            scheduled_receipts=scheduled_receipts
        )

        # Export to response
        projection_dict = projector.export_projection_to_dict(projection)

        return ProjectInventoryResponse(**projection_dict)

    except Exception as e:
        logger.error("Failed to project inventory",
                    tenant_id=tenant_id, error=str(e), exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_operations_route("replenishment-plans/inventory-projections"),
    response_model=List[InventoryProjectionResponse]
)
async def list_inventory_projections(
    tenant_id: UUID = Depends(get_current_tenant_id),
    ingredient_id: Optional[UUID] = None,
    projection_date: Optional[date] = None,
    stockout_only: bool = False,
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    db: AsyncSession = Depends(get_db)
):
    """
    List inventory projections
    """
    try:
        from app.repositories.replenishment_repository import InventoryProjectionRepository

        repo = InventoryProjectionRepository(db)
        projections = await repo.list_projections(
            tenant_id=tenant_id,
            ingredient_id=ingredient_id,
            projection_date=projection_date,
            stockout_only=stockout_only,
            skip=skip,
            limit=limit
        )

        return projections

    except Exception as e:
        logger.error("Failed to list inventory projections",
                    tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================
# Safety Stock Endpoints
# ============================================================

@router.post(
    route_builder.build_operations_route("replenishment-plans/safety-stock/calculate"),
    response_model=SafetyStockResponse
)
async def calculate_safety_stock(
    request: SafetyStockRequest,
    tenant_id: UUID = Depends(get_current_tenant_id)
):
    """
    Calculate dynamic safety stock using statistical methods
    """
    try:
        logger.info("Calculating safety stock", tenant_id=tenant_id,
                   ingredient_id=request.ingredient_id)

        calculator = SafetyStockCalculator(request.service_level)

        result = calculator.calculate_from_demand_history(
            daily_demands=request.daily_demands,
            lead_time_days=request.lead_time_days,
            service_level=request.service_level
        )

        return SafetyStockResponse(**calculator.export_to_dict(result))

    except Exception as e:
        logger.error("Failed to calculate safety stock",
                    tenant_id=tenant_id, error=str(e), exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================
# Supplier Selection Endpoints
# ============================================================

@router.post(
    route_builder.build_operations_route("replenishment-plans/supplier-selections/evaluate"),
    response_model=SupplierSelectionResult
)
async def evaluate_supplier_selection(
    request: SupplierSelectionRequest,
    tenant_id: UUID = Depends(get_current_tenant_id)
):
    """
    Evaluate supplier options using multi-criteria decision analysis
    """
    try:
        logger.info("Evaluating supplier selection", tenant_id=tenant_id,
                   ingredient_id=request.ingredient_id)

        selector = SupplierSelector()

        # Convert supplier options
        from app.services.supplier_selector import SupplierOption
        supplier_options = [
            SupplierOption(**opt) for opt in request.supplier_options
        ]

        result = selector.select_suppliers(
            ingredient_id=request.ingredient_id,
            ingredient_name=request.ingredient_name,
            required_quantity=request.required_quantity,
            supplier_options=supplier_options
        )

        return SupplierSelectionResult(**selector.export_result_to_dict(result))

    except Exception as e:
        logger.error("Failed to evaluate supplier selection",
                    tenant_id=tenant_id, error=str(e), exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_operations_route("replenishment-plans/supplier-allocations"),
    response_model=List[SupplierAllocationResponse]
)
async def list_supplier_allocations(
    tenant_id: UUID = Depends(get_current_tenant_id),
    requirement_id: Optional[UUID] = None,
    supplier_id: Optional[UUID] = None,
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    db: AsyncSession = Depends(get_db)
):
    """
    List supplier allocations
    """
    try:
        from app.repositories.replenishment_repository import SupplierAllocationRepository

        repo = SupplierAllocationRepository(db)
        allocations = await repo.list_allocations(
            tenant_id=tenant_id,
            requirement_id=requirement_id,
            supplier_id=supplier_id,
            skip=skip,
            limit=limit
        )

        return allocations

    except Exception as e:
        logger.error("Failed to list supplier allocations",
                    tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================
# MOQ Aggregation Endpoints
# ============================================================

@router.post(
    route_builder.build_operations_route("replenishment-plans/moq-aggregation/aggregate"),
    response_model=MOQAggregationResponse
)
async def aggregate_for_moq(
    request: MOQAggregationRequest,
    tenant_id: UUID = Depends(get_current_tenant_id)
):
    """
    Aggregate requirements to meet Minimum Order Quantities
    """
    try:
        logger.info("Aggregating requirements for MOQ", tenant_id=tenant_id)

        aggregator = MOQAggregator()

        # Convert requirements and constraints
        from app.services.moq_aggregator import (
            ProcurementRequirement as MOQReq,
            SupplierConstraints
        )

        requirements = [MOQReq(**req) for req in request.requirements]
        constraints = {
            k: SupplierConstraints(**v)
            for k, v in request.supplier_constraints.items()
        }

        # Aggregate
        aggregated_orders = aggregator.aggregate_requirements(
            requirements=requirements,
            supplier_constraints=constraints
        )

        # Calculate efficiency
        efficiency = aggregator.calculate_order_efficiency(aggregated_orders)

        return MOQAggregationResponse(
            aggregated_orders=[aggregator.export_to_dict(order) for order in aggregated_orders],
            efficiency_metrics=efficiency
        )

    except Exception as e:
        logger.error("Failed to aggregate for MOQ",
                    tenant_id=tenant_id, error=str(e), exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================
# Analytics Endpoints
# ============================================================

@router.get(
    route_builder.build_analytics_route("replenishment-plans"),
    response_model=ReplenishmentAnalytics
)
async def get_replenishment_analytics(
    tenant_id: UUID = Depends(get_current_tenant_id),
    start_date: Optional[date] = None,
    end_date: Optional[date] = None,
    db: AsyncSession = Depends(get_db)
):
    """
    Get replenishment planning analytics
    """
    try:
        from app.repositories.replenishment_repository import ReplenishmentAnalyticsRepository

        repo = ReplenishmentAnalyticsRepository(db)
        analytics = await repo.get_analytics(
            tenant_id=tenant_id,
            start_date=start_date,
            end_date=end_date
        )

        return analytics

    except Exception as e:
        logger.error("Failed to get replenishment analytics",
                    tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=str(e))
