# services/production/app/api/production_operations.py
"""
Production Operations API - Business operations for production management
Includes: batch start/complete, schedule finalize/optimize, capacity management, transformations, stats
"""

from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request, status
from typing import Optional
from datetime import date, datetime, timedelta
from uuid import UUID
import structlog

from shared.auth.decorators import get_current_user_dep
from shared.routing import RouteBuilder
from shared.monitoring.decorators import monitor_performance
from app.services.production_service import ProductionService
from app.schemas.production import (
    ProductionBatchResponse,
    ProductionScheduleResponse
)
from app.core.config import settings

logger = structlog.get_logger()
route_builder = RouteBuilder('production')
router = APIRouter(tags=["production-operations"])


def get_production_service(request: Request) -> ProductionService:
    """Dependency injection for production service"""
    from app.core.database import database_manager
    notification_service = getattr(request.app.state, 'notification_service', None)
    return ProductionService(database_manager, settings, notification_service)


# ===== BATCH OPERATIONS =====

@router.post(
    route_builder.build_nested_resource_route("batches", "batch_id", "start"),
    response_model=ProductionBatchResponse
)
async def start_production_batch(
    tenant_id: UUID = Path(...),
    batch_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Mark batch as started (updates actual_start_time)"""
    try:
        batch = await production_service.start_production_batch(tenant_id, batch_id)

        logger.info("Started production batch",
                   batch_id=str(batch_id), tenant_id=str(tenant_id))

        return ProductionBatchResponse.model_validate(batch)

    except ValueError as e:
        logger.warning("Cannot start batch", error=str(e), batch_id=str(batch_id))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error starting production batch",
                    error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to start production batch")


@router.post(
    route_builder.build_nested_resource_route("batches", "batch_id", "complete"),
    response_model=ProductionBatchResponse
)
async def complete_production_batch(
    tenant_id: UUID = Path(...),
    batch_id: UUID = Path(...),
    completion_data: Optional[dict] = None,
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Complete batch — auto-calculates yield, duration, cost summary"""
    try:
        batch = await production_service.complete_production_batch(tenant_id, batch_id, completion_data)

        logger.info("Completed production batch",
                   batch_id=str(batch_id), tenant_id=str(tenant_id))

        return ProductionBatchResponse.model_validate(batch)

    except ValueError as e:
        logger.warning("Cannot complete batch", error=str(e), batch_id=str(batch_id))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error completing production batch",
                    error=str(e), batch_id=str(batch_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to complete production batch")


@router.get(
    route_builder.build_operations_route("batches/stats"),
    response_model=dict
)
async def get_production_batch_stats(
    tenant_id: UUID = Path(...),
    start_date: Optional[date] = Query(None, description="Start date for stats"),
    end_date: Optional[date] = Query(None, description="End date for stats"),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Aggregated stats: completed vs failed, avg yield, on-time rate"""
    try:
        # Default to last 30 days if no dates provided
        if not start_date:
            start_date = (datetime.now() - timedelta(days=30)).date()
        if not end_date:
            end_date = datetime.now().date()

        stats = await production_service.get_batch_statistics(tenant_id, start_date, end_date)

        logger.info("Retrieved production batch statistics",
                   tenant_id=str(tenant_id), start_date=start_date.isoformat(), end_date=end_date.isoformat())

        return stats

    except Exception as e:
        logger.error("Error getting production batch stats",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get production batch stats")


# ===== SCHEDULE OPERATIONS =====

@router.post(
    route_builder.build_nested_resource_route("schedules", "schedule_id", "finalize"),
    response_model=ProductionScheduleResponse
)
async def finalize_production_schedule(
    tenant_id: UUID = Path(...),
    schedule_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Lock schedule; prevents further changes"""
    try:
        schedule = await production_service.finalize_production_schedule(tenant_id, schedule_id)

        logger.info("Finalized production schedule",
                   schedule_id=str(schedule_id), tenant_id=str(tenant_id))

        return ProductionScheduleResponse.model_validate(schedule)

    except ValueError as e:
        logger.warning("Cannot finalize schedule", error=str(e), schedule_id=str(schedule_id))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error finalizing production schedule",
                    error=str(e), schedule_id=str(schedule_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to finalize production schedule")


@router.get(
    route_builder.build_operations_route("schedules/optimize"),
    response_model=dict
)
async def optimize_production_schedule(
    tenant_id: UUID = Path(...),
    target_date: date = Query(..., description="Date to optimize"),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Trigger AI-based rescheduling suggestion based on demand/capacity"""
    try:
        optimization_result = await production_service.optimize_schedule(tenant_id, target_date)

        logger.info("Generated schedule optimization suggestions",
                   tenant_id=str(tenant_id), date=target_date.isoformat())

        return optimization_result

    except Exception as e:
        logger.error("Error optimizing production schedule",
                    error=str(e), tenant_id=str(tenant_id), date=target_date.isoformat())
        raise HTTPException(status_code=500, detail="Failed to optimize production schedule")


@router.get(
    route_builder.build_operations_route("schedules/capacity-usage"),
    response_model=dict
)
async def get_schedule_capacity_usage(
    tenant_id: UUID = Path(...),
    start_date: Optional[date] = Query(None),
    end_date: Optional[date] = Query(None),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Get capacity usage report for scheduling period"""
    try:
        if not start_date:
            start_date = datetime.now().date()
        if not end_date:
            end_date = start_date + timedelta(days=7)

        usage_report = await production_service.get_capacity_usage_report(tenant_id, start_date, end_date)

        logger.info("Retrieved capacity usage report",
                   tenant_id=str(tenant_id),
                   start_date=start_date.isoformat(),
                   end_date=end_date.isoformat())

        return usage_report

    except Exception as e:
        logger.error("Error getting capacity usage",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get capacity usage")


# ===== CAPACITY MANAGEMENT =====

@router.get(
    route_builder.build_operations_route("capacity/status"),
    response_model=dict
)
async def get_capacity_status(
    tenant_id: UUID = Path(...),
    target_date: Optional[date] = Query(None),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Get real-time capacity status"""
    try:
        if not target_date:
            target_date = datetime.now().date()

        status = await production_service.get_capacity_status(tenant_id, target_date)

        logger.info("Retrieved capacity status",
                   tenant_id=str(tenant_id), date=target_date.isoformat())

        return status

    except Exception as e:
        logger.error("Error getting capacity status",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get capacity status")


@router.get(
    route_builder.build_operations_route("capacity/availability"),
    response_model=dict
)
async def check_resource_availability(
    tenant_id: UUID = Path(...),
    target_date: date = Query(...),
    required_capacity: float = Query(..., gt=0),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Check if capacity is available for scheduling"""
    try:
        availability = await production_service.check_resource_availability(
            tenant_id, target_date, required_capacity
        )

        logger.info("Checked resource availability",
                   tenant_id=str(tenant_id),
                   date=target_date.isoformat(),
                   required=required_capacity)

        return availability

    except Exception as e:
        logger.error("Error checking resource availability",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to check resource availability")


@router.post(
    route_builder.build_operations_route("capacity/reserve"),
    response_model=dict
)
async def reserve_capacity(
    tenant_id: UUID = Path(...),
    target_date: date = Query(...),
    capacity_amount: float = Query(..., gt=0),
    batch_id: UUID = Query(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Reserve capacity for a batch"""
    try:
        reservation = await production_service.reserve_capacity(
            tenant_id, target_date, capacity_amount, batch_id
        )

        logger.info("Reserved production capacity",
                   tenant_id=str(tenant_id),
                   date=target_date.isoformat(),
                   amount=capacity_amount,
                   batch_id=str(batch_id))

        return reservation

    except ValueError as e:
        logger.warning("Cannot reserve capacity", error=str(e))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error reserving capacity",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to reserve capacity")


@router.get(
    "/api/v1/tenants/{tenant_id}/production/capacity/date/{date}",
    response_model=list
)
async def get_capacity_by_date(
    tenant_id: UUID = Path(...),
    date: date = Path(..., description="Date to retrieve capacity for (format: YYYY-MM-DD)"),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Get capacity by date (using direct route to support date path parameter)"""
    try:
        capacity_data = await production_service.get_capacity_by_date(tenant_id, date)

        logger.info("Retrieved capacity by date",
                   tenant_id=str(tenant_id), date=date.isoformat())

        return capacity_data

    except Exception as e:
        logger.error("Error getting capacity by date",
                    error=str(e), tenant_id=str(tenant_id), date=date.isoformat())
        raise HTTPException(status_code=500, detail="Failed to get capacity by date")


@router.get(
    route_builder.build_operations_route("capacity/bottlenecks"),
    response_model=dict
)
async def get_capacity_bottlenecks(
    tenant_id: UUID = Path(...),
    days_ahead: int = Query(7, ge=1, le=30),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Identify capacity bottlenecks in upcoming period"""
    try:
        bottlenecks = await production_service.predict_capacity_bottlenecks(tenant_id, days_ahead)

        logger.info("Retrieved capacity bottlenecks prediction",
                   tenant_id=str(tenant_id), days_ahead=days_ahead)

        return bottlenecks

    except Exception as e:
        logger.error("Error getting capacity bottlenecks",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get capacity bottlenecks")


# ===== TRANSFORMATION OPERATIONS =====

@router.post(
    route_builder.build_operations_route("batches/complete-with-transformation"),
    response_model=dict
)
async def complete_batch_with_transformation(
    tenant_id: UUID = Path(...),
    batch_id: UUID = Query(...),
    transformation_data: dict = None,
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Complete batch and create product transformation record"""
    try:
        result = await production_service.complete_batch_with_transformation(
            tenant_id, batch_id, transformation_data
        )

        logger.info("Completed batch with transformation",
                   tenant_id=str(tenant_id),
                   batch_id=str(batch_id))

        return result

    except ValueError as e:
        logger.warning("Cannot complete batch with transformation", error=str(e))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error completing batch with transformation",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to complete batch with transformation")


@router.post(
    route_builder.build_operations_route("transform-par-baked"),
    response_model=dict
)
async def transform_par_baked_products(
    tenant_id: UUID = Path(...),
    source_batch_id: UUID = Query(...),
    target_quantity: float = Query(..., gt=0),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Transform par-baked products to fully baked"""
    try:
        result = await production_service.transform_par_baked_to_fresh(
            tenant_id, source_batch_id, target_quantity
        )

        logger.info("Transformed par-baked products",
                   tenant_id=str(tenant_id),
                   source_batch_id=str(source_batch_id),
                   quantity=target_quantity)

        return result

    except ValueError as e:
        logger.warning("Cannot transform products", error=str(e))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error transforming products",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to transform products")


# ===== SCHEDULER OPERATIONS =====

@router.post(
    route_builder.build_operations_route("scheduler/trigger")
)
@monitor_performance("trigger_production_scheduler")
async def trigger_production_scheduler(
    tenant_id: UUID = Path(...),
    request: Request = None
):
    """
    Manually trigger the production scheduler for the current tenant

    This endpoint is primarily for testing and development purposes.
    Triggers the production schedule generation process manually.
    """
    try:
        # Get the scheduler service from app state
        if hasattr(request.app.state, 'scheduler_service'):
            scheduler_service = request.app.state.scheduler_service
            await scheduler_service.test_production_schedule_generation()

            logger.info("Production scheduler triggered manually",
                       tenant_id=str(tenant_id))

            return {
                "success": True,
                "message": "Production scheduler executed successfully",
                "tenant_id": str(tenant_id)
            }
        else:
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="Scheduler service is not available"
            )

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error triggering production scheduler",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error triggering production scheduler: {str(e)}"
        )
