"""
VRP Optimization API Endpoints
Endpoints for VRP optimization and metrics retrieval
"""

from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Dict, Any, Optional
from pydantic import BaseModel, Field
import structlog

from app.services.vrp_optimization_service import VRPOptimizationService
from app.services.distribution_service import DistributionService
from shared.auth.tenant_access import verify_tenant_permission_dep
from app.core.config import settings

logger = structlog.get_logger()
router = APIRouter()


# Pydantic models for request/response
class VRPOptimizationRequest(BaseModel):
    algorithm_version: str = Field(default="v2.1", description="VRP algorithm version to use")
    constraints: Optional[Dict[str, Any]] = Field(
        None, 
        description="Optimization constraints: max_route_duration, max_route_distance, etc."
    )


class VRPOptimizationResponse(BaseModel):
    success: bool
    route_id: str
    optimization_savings: Dict[str, Any]
    vrp_algorithm_version: str
    vrp_optimization_timestamp: str
    vrp_constraints_satisfied: bool
    vrp_objective_value: float


class RouteOptimizationMetrics(BaseModel):
    route_id: str
    route_number: str
    route_date: str
    vrp_optimization_savings: Optional[Dict[str, Any]]
    vrp_algorithm_version: Optional[str]
    vrp_optimization_timestamp: Optional[str]
    vrp_constraints_satisfied: Optional[bool]
    vrp_objective_value: Optional[float]
    total_distance_km: Optional[float]
    estimated_duration_minutes: Optional[int]


class NetworkOptimizationSummary(BaseModel):
    total_routes: int
    optimized_routes: int
    total_distance_saved_km: float
    total_time_saved_minutes: float
    total_fuel_saved_liters: float
    total_co2_saved_kg: float
    total_cost_saved_eur: float
    optimization_rate: float
    average_savings_per_route: Optional[Dict[str, Any]]


class OptimizationHistoryItem(BaseModel):
    optimization_id: str
    route_id: str
    timestamp: str
    algorithm_version: str
    distance_saved_km: float
    time_saved_minutes: float
    fuel_saved_liters: float
    co2_saved_kg: float
    cost_saved_eur: float
    constraints_satisfied: bool


async def get_vrp_optimization_service() -> VRPOptimizationService:
    """Dependency injection for VRPOptimizationService"""
    from app.core.database import database_manager
    from app.services.distribution_service import DistributionService as BusinessDistributionService
    from app.repositories.delivery_route_repository import DeliveryRouteRepository
    from app.repositories.shipment_repository import ShipmentRepository
    from app.repositories.delivery_schedule_repository import DeliveryScheduleRepository
    from shared.clients.tenant_client import TenantServiceClient
    from shared.clients.inventory_client import InventoryServiceClient
    from shared.clients.procurement_client import ProcurementServiceClient
    from app.services.routing_optimizer import RoutingOptimizer
    
    # Create the business distribution service with proper dependencies
    route_repository = DeliveryRouteRepository(database_manager.get_session())
    shipment_repository = ShipmentRepository(database_manager.get_session())
    schedule_repository = DeliveryScheduleRepository(database_manager.get_session())
    
    # Create client instances (these will be initialized with proper config)
    tenant_client = TenantServiceClient()
    inventory_client = InventoryServiceClient()
    procurement_client = ProcurementServiceClient()
    routing_optimizer = RoutingOptimizer()
    
    distribution_service = BusinessDistributionService(
        route_repository=route_repository,
        shipment_repository=shipment_repository,
        schedule_repository=schedule_repository,
        procurement_client=procurement_client,
        tenant_client=tenant_client,
        inventory_client=inventory_client,
        routing_optimizer=routing_optimizer
    )
    
    return VRPOptimizationService(distribution_service, database_manager)


@router.post("/tenants/{tenant_id}/routes/{route_id}/optimize",
            response_model=VRPOptimizationResponse,
            summary="Optimize delivery route with VRP")
async def optimize_route_with_vrp(
    tenant_id: str,
    route_id: str,
    optimization_request: VRPOptimizationRequest,
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Optimize a delivery route using VRP algorithm
    
    This endpoint applies VRP optimization to a specific delivery route and stores
    the optimization metrics for analysis and reporting.
    """
    try:
        result = await vrp_service.optimize_route_with_vrp(
            route_id=route_id,
            algorithm_version=optimization_request.algorithm_version,
            constraints=optimization_request.constraints
        )
        
        if not result.get('success'):
            raise HTTPException(status_code=500, detail="Optimization failed")
        
        return VRPOptimizationResponse(
            success=True,
            route_id=result['route_id'],
            optimization_savings=result['optimization_savings'],
            vrp_algorithm_version=result['optimization_savings'].get('algorithm_version', optimization_request.algorithm_version),
            vrp_optimization_timestamp=result['optimization_savings'].get('timestamp', datetime.now().isoformat()),
            vrp_constraints_satisfied=result['optimization_savings'].get('constraints_satisfied', True),
            vrp_objective_value=result['optimization_savings'].get('objective_value', 0.0)
        )
        
    except Exception as e:
        logger.error("VRP optimization failed", tenant_id=tenant_id, route_id=route_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"VRP optimization failed: {str(e)}")


@router.get("/tenants/{tenant_id}/routes/{route_id}/optimization-metrics",
           response_model=RouteOptimizationMetrics,
           summary="Get VRP optimization metrics for route")
async def get_route_optimization_metrics(
    tenant_id: str,
    route_id: str,
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get VRP optimization metrics for a specific route
    
    Retrieves stored optimization metrics including savings, algorithm version,
    and constraint satisfaction status.
    """
    try:
        metrics = await vrp_service.get_route_optimization_metrics(route_id)
        return RouteOptimizationMetrics(**metrics)
        
    except Exception as e:
        logger.error("Failed to get route optimization metrics", tenant_id=tenant_id, route_id=route_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get optimization metrics: {str(e)}")


@router.get("/tenants/{tenant_id}/vrp/optimization-summary",
           response_model=NetworkOptimizationSummary,
           summary="Get network-wide VRP optimization summary")
async def get_network_optimization_summary(
    tenant_id: str,
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get aggregated VRP optimization metrics across all routes
    
    Provides network-wide summary of optimization benefits including
    total savings, optimization rate, and average improvements.
    """
    try:
        summary = await vrp_service.get_network_optimization_summary(tenant_id)
        return NetworkOptimizationSummary(**summary)
        
    except Exception as e:
        logger.error("Failed to get network optimization summary", tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get optimization summary: {str(e)}")


@router.post("/tenants/{tenant_id}/vrp/batch-optimize",
            summary="Batch optimize multiple routes")
async def batch_optimize_routes(
    tenant_id: str,
    route_ids: List[str] = Query(..., description="List of route IDs to optimize"),
    algorithm_version: str = Query("v2.1", description="VRP algorithm version"),
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Batch optimize multiple delivery routes with VRP
    
    Applies VRP optimization to multiple routes in a single request.
    """
    try:
        result = await vrp_service.batch_optimize_routes(tenant_id, route_ids)
        
        return {
            'success': True,
            'total_routes_processed': result['total_routes_processed'],
            'successful_optimizations': result['successful_optimizations'],
            'failed_optimizations': result['failed_optimizations'],
            'results': result['results']
        }
        
    except Exception as e:
        logger.error("Batch optimization failed", tenant_id=tenant_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"Batch optimization failed: {str(e)}")


@router.get("/tenants/{tenant_id}/routes/{route_id}/optimization-history",
           response_model=List[OptimizationHistoryItem],
           summary="Get optimization history for route")
async def get_optimization_history(
    tenant_id: str,
    route_id: str,
    limit: int = Query(10, description="Maximum number of historical records to return"),
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get historical optimization records for a route
    
    Retrieves past optimization runs and their results for analysis.
    """
    try:
        history = await vrp_service.get_optimization_history(route_id, limit)
        return [OptimizationHistoryItem(**item) for item in history]
        
    except Exception as e:
        logger.error("Failed to get optimization history", tenant_id=tenant_id, route_id=route_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get optimization history: {str(e)}")


@router.get("/tenants/{tenant_id}/vrp/constraints/validate",
           summary="Validate VRP constraints")
async def validate_vrp_constraints(
    tenant_id: str,
    route_id: str,
    max_route_duration: Optional[int] = Query(None, description="Maximum route duration in minutes"),
    max_route_distance: Optional[float] = Query(None, description="Maximum route distance in km"),
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Validate VRP constraints against a route
    
    Checks if a route satisfies specified VRP constraints.
    """
    try:
        from app.services.vrp_optimization_service import VRPConstraintValidator
        
        # Get route data
        route = await vrp_service.distribution_service.get_delivery_route(route_id)
        
        if not route:
            raise HTTPException(status_code=404, detail="Route not found")
        
        # Build constraints dict
        constraints = {}
        if max_route_duration is not None:
            constraints['max_route_duration'] = max_route_duration
        if max_route_distance is not None:
            constraints['max_route_distance'] = max_route_distance
        
        # Validate constraints
        validation_result = VRPConstraintValidator.validate_constraints(route, constraints)
        
        return {
            'success': True,
            'all_constraints_satisfied': validation_result['all_satisfied'],
            'constraint_violations': validation_result['constraint_violations']
        }
        
    except Exception as e:
        logger.error("Failed to validate VRP constraints", tenant_id=tenant_id, route_id=route_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to validate constraints: {str(e)}")


@router.post("/tenants/{tenant_id}/vrp/simulate",
            summary="Simulate VRP optimization")
async def simulate_vrp_optimization(
    tenant_id: str,
    route_id: str,
    vrp_service: VRPOptimizationService = Depends(get_vrp_optimization_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Simulate VRP optimization without saving results
    
    Useful for testing and previewing optimization results.
    """
    try:
        from app.services.vrp_optimization_service import VRPOptimizationSimulator
        
        # Get route data
        route = await vrp_service.distribution_service.get_delivery_route(route_id)
        
        if not route:
            raise HTTPException(status_code=404, detail="Route not found")
        
        # Simulate optimization
        simulation_result = VRPOptimizationSimulator.simulate_optimization(route)
        
        return {
            'success': True,
            'original_route': simulation_result['original_route'],
            'optimized_route': simulation_result['optimized_route'],
            'optimization_savings': simulation_result['optimization_savings'],
            'algorithm_version': simulation_result['algorithm_version'],
            'constraints_satisfied': simulation_result['constraints_satisfied'],
            'objective_value': simulation_result['objective_value']
        }
        
    except Exception as e:
        logger.error("VRP simulation failed", tenant_id=tenant_id, route_id=route_id, error=str(e))
        raise HTTPException(status_code=500, detail=f"VRP simulation failed: {str(e)}")


# Import datetime at runtime to avoid circular imports
from datetime import datetime