# ================================================================
# services/orders/app/api/procurement.py
# ================================================================
"""
Procurement API Endpoints - RESTful APIs for procurement planning
"""

import uuid
from datetime import date
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.config import settings
from app.services.procurement_service import ProcurementService
from app.schemas.procurement_schemas import (
    ProcurementPlanResponse, GeneratePlanRequest, GeneratePlanResponse,
    DashboardData, PaginatedProcurementPlans
)
from shared.auth.decorators import require_authentication, get_current_user_dep
from fastapi import Depends, Request
from typing import Dict, Any
import uuid
from shared.clients.inventory_client import InventoryServiceClient
from shared.clients.forecast_client import ForecastServiceClient
from shared.config.base import BaseServiceSettings
from shared.monitoring.decorators import monitor_performance

# Create router - tenant-scoped
router = APIRouter(prefix="/tenants/{tenant_id}", tags=["Procurement Planning"])

# Create service settings
service_settings = BaseServiceSettings()

# Simple TenantAccess class for compatibility
class TenantAccess:
    def __init__(self, tenant_id: uuid.UUID, user_id: str):
        self.tenant_id = tenant_id
        self.user_id = user_id

async def get_current_tenant(
    request: Request,
    current_user: Dict[str, Any] = Depends(get_current_user_dep)
) -> TenantAccess:
    """Get current tenant from user context"""
    # For now, create a simple tenant access from user data
    # In a real implementation, this would validate tenant access
    tenant_id = current_user.get('tenant_id')
    if not tenant_id:
        # Try to get from headers as fallback
        tenant_id = request.headers.get('x-tenant-id')
    
    if not tenant_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Tenant access required"
        )
    
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except (ValueError, TypeError):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid tenant ID format"
        )
    
    return TenantAccess(
        tenant_id=tenant_uuid,
        user_id=current_user['user_id']
    )


async def get_procurement_service(db: AsyncSession = Depends(get_db)) -> ProcurementService:
    """Get procurement service instance"""
    inventory_client = InventoryServiceClient(service_settings)
    forecast_client = ForecastServiceClient(service_settings, "orders-service")
    return ProcurementService(db, service_settings, inventory_client, forecast_client)


# ================================================================
# PROCUREMENT PLAN ENDPOINTS
# ================================================================

@router.get("/procurement/plans/current", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_current_procurement_plan")
async def get_current_procurement_plan(
    tenant_id: uuid.UUID,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get the procurement plan for the current day (forecasting for the next day)
    
    Returns the plan details, including requirements per item.
    """
    try:
        plan = await procurement_service.get_current_plan(tenant_access.tenant_id)
        return plan
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving current procurement plan: {str(e)}"
        )


@router.get("/procurement/plans/date/{plan_date}", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_procurement_plan_by_date")
async def get_procurement_plan_by_date(
    tenant_id: uuid.UUID,
    plan_date: date,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get the procurement plan for a specific date (format: YYYY-MM-DD)
    
    Returns the plan details, including requirements per item for the specified date.
    """
    try:
        plan = await procurement_service.get_plan_by_date(tenant_access.tenant_id, plan_date)
        return plan
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving procurement plan for {plan_date}: {str(e)}"
        )


@router.get("/procurement/plans", response_model=PaginatedProcurementPlans)
@monitor_performance("list_procurement_plans")
async def list_procurement_plans(
    tenant_id: uuid.UUID,
    status: Optional[str] = Query(None, description="Filter by plan status"),
    start_date: Optional[date] = Query(None, description="Start date filter (YYYY-MM-DD)"),
    end_date: Optional[date] = Query(None, description="End date filter (YYYY-MM-DD)"),
    limit: int = Query(50, ge=1, le=100, description="Number of plans to return"),
    offset: int = Query(0, ge=0, description="Number of plans to skip"),
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    List procurement plans with optional filters
    
    Supports filtering by status, date range, and pagination.
    """
    try:
        # Get plans from repository directly for listing
        plans = await procurement_service.plan_repo.list_plans(
            tenant_access.tenant_id,
            status=status,
            start_date=start_date,
            end_date=end_date,
            limit=limit,
            offset=offset
        )
        
        # Convert to response models
        plan_responses = [ProcurementPlanResponse.model_validate(plan) for plan in plans]
        
        # For simplicity, we'll use the returned count as total
        # In a production system, you'd want a separate count query
        total = len(plan_responses)
        has_more = len(plan_responses) == limit
        
        return PaginatedProcurementPlans(
            plans=plan_responses,
            total=total,
            page=offset // limit + 1 if limit > 0 else 1,
            limit=limit,
            has_more=has_more
        )
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error listing procurement plans: {str(e)}"
        )


@router.post("/procurement/plans/generate", response_model=GeneratePlanResponse)
@monitor_performance("generate_procurement_plan")
async def generate_procurement_plan(
    tenant_id: uuid.UUID,
    request: GeneratePlanRequest,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Manually trigger the generation of a procurement plan
    
    This can serve as a fallback if the daily scheduler hasn't run,
    or for testing purposes. Can be forced to regenerate an existing plan.
    """
    try:
        if not settings.PROCUREMENT_PLANNING_ENABLED:
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="Procurement planning is currently disabled"
            )
        
        result = await procurement_service.generate_procurement_plan(
            tenant_access.tenant_id,
            request
        )
        
        if not result.success:
            # Return the result with errors but don't raise an exception
            # since the service method handles the error state properly
            return result
        
        return result
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error generating procurement plan: {str(e)}"
        )


@router.put("/procurement/plans/{plan_id}/status")
@monitor_performance("update_procurement_plan_status")
async def update_procurement_plan_status(
    tenant_id: uuid.UUID,
    plan_id: uuid.UUID,
    status: str = Query(..., description="New status", pattern="^(draft|pending_approval|approved|in_execution|completed|cancelled)$"),
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Update the status of a procurement plan
    
    Valid statuses: draft, pending_approval, approved, in_execution, completed, cancelled
    """
    try:
        updated_plan = await procurement_service.update_plan_status(
            tenant_access.tenant_id,
            plan_id,
            status,
            tenant_access.user_id
        )
        
        if not updated_plan:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Procurement plan not found"
            )
        
        return updated_plan
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error updating procurement plan status: {str(e)}"
        )


@router.get("/procurement/plans/id/{plan_id}", response_model=Optional[ProcurementPlanResponse])
@monitor_performance("get_procurement_plan_by_id")
async def get_procurement_plan_by_id(
    tenant_id: uuid.UUID,
    plan_id: uuid.UUID,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get a specific procurement plan by its ID
    
    Returns detailed plan information including all requirements.
    """
    try:
        plan = await procurement_service.get_plan_by_id(tenant_access.tenant_id, plan_id)
        
        if not plan:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Procurement plan not found"
            )
        
        return plan
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving procurement plan: {str(e)}"
        )


# ================================================================
# DASHBOARD ENDPOINTS
# ================================================================

@router.get("/procurement/dashboard", response_model=Optional[DashboardData])
@monitor_performance("get_procurement_dashboard")
async def get_procurement_dashboard(
    tenant_id: uuid.UUID,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get procurement dashboard data
    
    Returns comprehensive dashboard information including:
    - Current plan
    - Summary statistics  
    - Upcoming deliveries
    - Overdue requirements
    - Low stock alerts
    - Performance metrics
    """
    try:
        dashboard_data = await procurement_service.get_dashboard_data(tenant_access.tenant_id)
        return dashboard_data
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving dashboard data: {str(e)}"
        )


# ================================================================
# REQUIREMENT MANAGEMENT ENDPOINTS
# ================================================================

@router.get("/procurement/plans/{plan_id}/requirements")
@monitor_performance("get_plan_requirements")
async def get_plan_requirements(
    tenant_id: uuid.UUID,
    plan_id: uuid.UUID,
    status: Optional[str] = Query(None, description="Filter by requirement status"),
    priority: Optional[str] = Query(None, description="Filter by priority level"),
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get all requirements for a specific procurement plan
    
    Supports filtering by status and priority level.
    """
    try:
        # Verify plan exists and belongs to tenant
        plan = await procurement_service.get_plan_by_id(tenant_access.tenant_id, plan_id)
        if not plan:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Procurement plan not found"
            )
        
        # Get requirements from repository
        requirements = await procurement_service.requirement_repo.get_requirements_by_plan(plan_id)
        
        # Apply filters if provided
        if status:
            requirements = [r for r in requirements if r.status == status]
        if priority:
            requirements = [r for r in requirements if r.priority == priority]
        
        return requirements
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving plan requirements: {str(e)}"
        )


@router.get("/procurement/requirements/critical")
@monitor_performance("get_critical_requirements")
async def get_critical_requirements(
    tenant_id: uuid.UUID,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Get all critical priority requirements across all active plans
    
    Returns requirements that need immediate attention.
    """
    try:
        requirements = await procurement_service.requirement_repo.get_critical_requirements(
            tenant_access.tenant_id
        )
        return requirements
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error retrieving critical requirements: {str(e)}"
        )


# ================================================================
# UTILITY ENDPOINTS
# ================================================================

@router.post("/procurement/scheduler/trigger")
@monitor_performance("trigger_daily_scheduler")
async def trigger_daily_scheduler(
    tenant_id: uuid.UUID,
    tenant_access: TenantAccess = Depends(get_current_tenant),
    procurement_service: ProcurementService = Depends(get_procurement_service)
):
    """
    Manually trigger the daily scheduler for the current tenant
    
    This endpoint is primarily for testing and maintenance purposes.
    """
    try:
        # Process daily plan for current tenant only
        await procurement_service._process_daily_plan_for_tenant(tenant_access.tenant_id)
        
        return {
            "success": True,
            "message": "Daily scheduler executed successfully",
            "tenant_id": str(tenant_access.tenant_id)
        }
        
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error triggering daily scheduler: {str(e)}"
        )


@router.get("/procurement/health")
async def procurement_health_check():
    """
    Health check endpoint for procurement service
    """
    return {
        "status": "healthy",
        "service": "procurement-planning",
        "procurement_enabled": settings.PROCUREMENT_PLANNING_ENABLED,
        "timestamp": date.today().isoformat()
    }