"""
Enterprise Inventory API Endpoints
APIs for enterprise-level inventory management across outlets
"""

from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
from datetime import date
from pydantic import BaseModel, Field
import structlog

from app.services.enterprise_inventory_service import EnterpriseInventoryService
from shared.auth.tenant_access import verify_tenant_permission_dep
from shared.clients import get_inventory_client, get_tenant_client
from app.core.config import settings

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


# Pydantic models for request/response
class InventoryCoverageResponse(BaseModel):
    outlet_id: str = Field(..., description="Outlet tenant ID")
    outlet_name: str = Field(..., description="Outlet name")
    overall_coverage: float = Field(..., description="Overall inventory coverage percentage (0-100)")
    critical_items_count: int = Field(..., description="Number of items at critical stock levels")
    high_risk_items_count: int = Field(..., description="Number of items at high risk of stockout")
    medium_risk_items_count: int = Field(..., description="Number of items at medium risk")
    low_risk_items_count: int = Field(..., description="Number of items at low risk")
    fulfillment_rate: float = Field(..., description="Order fulfillment rate percentage (0-100)")
    last_updated: str = Field(..., description="Last inventory update timestamp")
    status: str = Field(..., description="Overall status: normal, warning, critical")


class ProductCoverageDetail(BaseModel):
    product_id: str = Field(..., description="Product ID")
    product_name: str = Field(..., description="Product name")
    current_stock: int = Field(..., description="Current stock quantity")
    safety_stock: int = Field(..., description="Safety stock threshold")
    coverage_percentage: float = Field(..., description="Coverage percentage (current/safety)")
    risk_level: str = Field(..., description="Risk level: critical, high, medium, low")
    days_until_stockout: Optional[int] = Field(None, description="Estimated days until stockout")


class OutletInventoryDetailResponse(BaseModel):
    outlet_id: str = Field(..., description="Outlet tenant ID")
    outlet_name: str = Field(..., description="Outlet name")
    overall_coverage: float = Field(..., description="Overall inventory coverage percentage")
    products: List[ProductCoverageDetail] = Field(..., description="Product-level inventory details")
    last_updated: str = Field(..., description="Last update timestamp")


class NetworkInventorySummary(BaseModel):
    total_outlets: int = Field(..., description="Total number of outlets")
    average_coverage: float = Field(..., description="Network average inventory coverage")
    average_fulfillment_rate: float = Field(..., description="Network average fulfillment rate")
    critical_outlets: int = Field(..., description="Number of outlets with critical status")
    warning_outlets: int = Field(..., description="Number of outlets with warning status")
    normal_outlets: int = Field(..., description="Number of outlets with normal status")
    total_critical_items: int = Field(..., description="Total critical items across network")
    network_health_score: float = Field(..., description="Overall network health score (0-100)")


class InventoryAlert(BaseModel):
    alert_id: str = Field(..., description="Alert ID")
    outlet_id: str = Field(..., description="Outlet ID")
    outlet_name: str = Field(..., description="Outlet name")
    product_id: Optional[str] = Field(None, description="Product ID if applicable")
    product_name: Optional[str] = Field(None, description="Product name if applicable")
    alert_type: str = Field(..., description="Type of alert: stockout_risk, low_coverage, etc.")
    severity: str = Field(..., description="Severity: critical, high, medium, low")
    current_coverage: float = Field(..., description="Current inventory coverage percentage")
    threshold: float = Field(..., description="Threshold that triggered alert")
    timestamp: str = Field(..., description="Alert timestamp")
    message: str = Field(..., description="Alert message")


async def get_enterprise_inventory_service() -> "EnterpriseInventoryService":
    """Dependency injection for EnterpriseInventoryService"""
    inventory_client = get_inventory_client(settings, "inventory-service")
    tenant_client = get_tenant_client(settings, "inventory-service")
    return EnterpriseInventoryService(
        inventory_client=inventory_client,
        tenant_client=tenant_client
    )


@router.get("/tenants/{parent_id}/outlets/inventory-coverage", 
           response_model=List[InventoryCoverageResponse],
           summary="Get inventory coverage for all outlets in network")
async def get_outlet_inventory_coverage(
    parent_id: str,
    min_coverage: Optional[float] = Query(None, description="Filter outlets with coverage below this threshold"),
    risk_level: Optional[str] = Query(None, description="Filter by risk level: critical, high, medium, low"),
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get inventory coverage metrics for all child outlets in a parent tenant's network
    
    This endpoint provides a comprehensive view of inventory health across all outlets,
    enabling enterprise managers to identify stockout risks and prioritize inventory transfers.
    """
    try:
        # Verify this is a parent tenant
        tenant_info = await enterprise_inventory_service.tenant_client.get_tenant(parent_id)
        if tenant_info.get('tenant_type') != 'parent':
            raise HTTPException(
                status_code=403,
                detail="Only parent tenants can access outlet inventory coverage"
            )
        
        # Get all child outlets for this parent
        child_outlets = await enterprise_inventory_service.get_child_outlets(parent_id)
        
        if not child_outlets:
            return []
        
        # Get inventory coverage for each outlet
        coverage_data = []
        for outlet in child_outlets:
            outlet_id = outlet['id']
            
            # Get inventory coverage data
            coverage = await enterprise_inventory_service.get_inventory_coverage(outlet_id)
            
            if coverage:
                # Apply filters if specified
                if min_coverage is not None and coverage['overall_coverage'] >= min_coverage:
                    continue
                if risk_level is not None and coverage.get('status') != risk_level:
                    continue
                
                coverage_data.append(coverage)
        
        # Sort by coverage (lowest first) to prioritize critical outlets
        coverage_data.sort(key=lambda x: x['overall_coverage'])
        
        return coverage_data
        
    except Exception as e:
        logger.error("Failed to get outlet inventory coverage", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get inventory coverage: {str(e)}")


@router.get("/tenants/{parent_id}/outlets/inventory-summary", 
           response_model=NetworkInventorySummary,
           summary="Get network-wide inventory summary")
async def get_network_inventory_summary(
    parent_id: str,
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get aggregated inventory summary across the entire network
    
    Provides key metrics for network health monitoring and decision making.
    """
    try:
        # Verify this is a parent tenant
        tenant_info = await enterprise_inventory_service.tenant_client.get_tenant(parent_id)
        if tenant_info.get('tenant_type') != 'parent':
            raise HTTPException(
                status_code=403,
                detail="Only parent tenants can access network inventory summary"
            )
        
        return await enterprise_inventory_service.get_network_inventory_summary(parent_id)
        
    except Exception as e:
        logger.error("Failed to get network inventory summary", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get inventory summary: {str(e)}")


@router.get("/tenants/{parent_id}/outlets/{outlet_id}/inventory-details", 
           response_model=OutletInventoryDetailResponse,
           summary="Get detailed inventory for specific outlet")
async def get_outlet_inventory_details(
    parent_id: str,
    outlet_id: str,
    product_id: Optional[str] = Query(None, description="Filter by specific product ID"),
    risk_level: Optional[str] = Query(None, description="Filter products by risk level"),
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get detailed product-level inventory data for a specific outlet
    
    Enables drill-down analysis of inventory issues at the product level.
    """
    try:
        # Verify parent-child relationship
        await enterprise_inventory_service.verify_parent_child_relationship(parent_id, outlet_id)
        
        return await enterprise_inventory_service.get_outlet_inventory_details(outlet_id, product_id, risk_level)
        
    except Exception as e:
        logger.error("Failed to get outlet inventory details", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get inventory details: {str(e)}")


@router.get("/tenants/{parent_id}/inventory-alerts", 
           response_model=List[InventoryAlert],
           summary="Get real-time inventory alerts across network")
async def get_network_inventory_alerts(
    parent_id: str,
    severity: Optional[str] = Query(None, description="Filter by severity: critical, high, medium, low"),
    alert_type: Optional[str] = Query(None, description="Filter by alert type"),
    limit: int = Query(50, description="Maximum number of alerts to return"),
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get real-time inventory alerts across all outlets
    
    Provides actionable alerts for inventory management and stockout prevention.
    """
    try:
        # Verify this is a parent tenant
        tenant_info = await enterprise_inventory_service.tenant_client.get_tenant(parent_id)
        if tenant_info.get('tenant_type') != 'parent':
            raise HTTPException(
                status_code=403,
                detail="Only parent tenants can access network inventory alerts"
            )
        
        alerts = await enterprise_inventory_service.get_inventory_alerts(parent_id)
        
        # Apply filters
        if severity:
            alerts = [alert for alert in alerts if alert.get('severity') == severity]
        if alert_type:
            alerts = [alert for alert in alerts if alert.get('alert_type') == alert_type]
        
        # Sort by severity (critical first) and timestamp (newest first)
        severity_order = {'critical': 1, 'high': 2, 'medium': 3, 'low': 4}
        alerts.sort(key=lambda x: (severity_order.get(x.get('severity', 'low'), 5), -int(x.get('timestamp', 0))))
        
        return alerts[:limit]
        
    except Exception as e:
        logger.error("Failed to get inventory alerts", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get inventory alerts: {str(e)}")


@router.post("/tenants/{parent_id}/inventory-transfers/recommend", 
            summary="Get inventory transfer recommendations")
async def get_inventory_transfer_recommendations(
    parent_id: str,
    urgency: str = Query("medium", description="Urgency level: low, medium, high, critical"),
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get AI-powered inventory transfer recommendations
    
    Analyzes inventory levels across outlets and suggests optimal transfers
    to prevent stockouts and balance inventory.
    """
    try:
        # Verify this is a parent tenant
        tenant_info = await enterprise_inventory_service.tenant_client.get_tenant(parent_id)
        if tenant_info.get('tenant_type') != 'parent':
            raise HTTPException(
                status_code=403,
                detail="Only parent tenants can request transfer recommendations"
            )
        
        recommendations = await enterprise_inventory_service.get_transfer_recommendations(parent_id, urgency)
        
        return {
            'success': True,
            'recommendations': recommendations,
            'message': f'Generated {len(recommendations)} transfer recommendations'
        }
        
    except Exception as e:
        logger.error("Failed to get transfer recommendations", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get recommendations: {str(e)}")


@router.get("/tenants/{parent_id}/inventory/coverage-trends", 
           summary="Get inventory coverage trends over time")
async def get_inventory_coverage_trends(
    parent_id: str,
    days: int = Query(30, description="Number of days to analyze"),
    enterprise_inventory_service: EnterpriseInventoryService = Depends(get_enterprise_inventory_service),
    verified_tenant: str = Depends(verify_tenant_permission_dep)
):
    """
    Get historical inventory coverage trends
    
    Enables analysis of inventory performance over time.
    """
    try:
        # Verify this is a parent tenant
        tenant_info = await enterprise_inventory_service.tenant_client.get_tenant(parent_id)
        if tenant_info.get('tenant_type') != 'parent':
            raise HTTPException(
                status_code=403,
                detail="Only parent tenants can access coverage trends"
            )
        
        trends = await enterprise_inventory_service.get_coverage_trends(parent_id, days)
        
        return {
            'success': True,
            'trends': trends,
            'period': f'Last {days} days'
        }
        
    except Exception as e:
        logger.error("Failed to get coverage trends", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to get coverage trends: {str(e)}")
