# ================================================================
# services/orchestrator/app/api/orchestration.py
# ================================================================
"""
Orchestration API Endpoints
Testing and manual trigger endpoints for orchestration
"""

import uuid
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field
import structlog

from app.core.database import get_db
from app.repositories.orchestration_run_repository import OrchestrationRunRepository
from sqlalchemy.ext.asyncio import AsyncSession

logger = structlog.get_logger()

router = APIRouter(prefix="/api/v1/tenants/{tenant_id}/orchestrator", tags=["Orchestration"])


# ================================================================
# REQUEST/RESPONSE SCHEMAS
# ================================================================

class OrchestratorTestRequest(BaseModel):
    """Request schema for testing orchestrator"""
    test_scenario: Optional[str] = Field(None, description="Test scenario: full, production_only, procurement_only")
    dry_run: bool = Field(False, description="Dry run mode (no actual changes)")


class OrchestratorTestResponse(BaseModel):
    """Response schema for orchestrator test"""
    success: bool
    message: str
    tenant_id: str
    forecasting_completed: bool = False
    production_completed: bool = False
    procurement_completed: bool = False
    notifications_sent: bool = False
    summary: dict = {}


class OrchestratorWorkflowRequest(BaseModel):
    """Request schema for daily workflow trigger"""
    dry_run: bool = Field(False, description="Dry run mode (no actual changes)")


class OrchestratorWorkflowResponse(BaseModel):
    """Response schema for daily workflow trigger"""
    success: bool
    message: str
    tenant_id: str
    run_id: Optional[str] = None
    forecasting_completed: bool = False
    production_completed: bool = False
    procurement_completed: bool = False
    notifications_sent: bool = False
    summary: dict = {}


# ================================================================
# API ENDPOINTS
# ================================================================

@router.post("/test", response_model=OrchestratorTestResponse)
async def trigger_orchestrator_test(
    tenant_id: str,
    request_data: OrchestratorTestRequest,
    request: Request,
    db: AsyncSession = Depends(get_db)
):
    """
    Trigger orchestrator for testing purposes

    This endpoint allows manual triggering of the orchestration workflow
    for a specific tenant, useful for testing during development.

    Args:
        tenant_id: Tenant ID to orchestrate
        request_data: Test request with scenario and dry_run options
        request: FastAPI request object
        db: Database session

    Returns:
        OrchestratorTestResponse with results
    """
    logger.info("Orchestrator test trigger requested",
               tenant_id=tenant_id,
               test_scenario=request_data.test_scenario,
               dry_run=request_data.dry_run)

    try:
        # Get scheduler service from app state
        if not hasattr(request.app.state, 'scheduler_service'):
            raise HTTPException(
                status_code=503,
                detail="Orchestrator scheduler service not available"
            )

        scheduler_service = request.app.state.scheduler_service

        # Trigger orchestration
        tenant_uuid = uuid.UUID(tenant_id)
        result = await scheduler_service.trigger_orchestration_for_tenant(
            tenant_id=tenant_uuid,
            test_scenario=request_data.test_scenario
        )

        # Get the latest run for this tenant
        repo = OrchestrationRunRepository(db)
        latest_run = await repo.get_latest_run_for_tenant(tenant_uuid)

        # Build response
        response = OrchestratorTestResponse(
            success=result.get('success', False),
            message=result.get('message', 'Orchestration completed'),
            tenant_id=tenant_id,
            forecasting_completed=latest_run.forecasting_status == 'success' if latest_run else False,
            production_completed=latest_run.production_status == 'success' if latest_run else False,
            procurement_completed=latest_run.procurement_status == 'success' if latest_run else False,
            notifications_sent=latest_run.notification_status == 'success' if latest_run else False,
            summary={
                'forecasts_generated': latest_run.forecasts_generated if latest_run else 0,
                'batches_created': latest_run.production_batches_created if latest_run else 0,
                'pos_created': latest_run.purchase_orders_created if latest_run else 0,
                'notifications_sent': latest_run.notifications_sent if latest_run else 0
            }
        )

        logger.info("Orchestrator test completed",
                   tenant_id=tenant_id,
                   success=response.success)

        return response

    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"Invalid tenant ID: {str(e)}")
    except Exception as e:
        logger.error("Orchestrator test failed",
                    tenant_id=tenant_id,
                    error=str(e),
                    exc_info=True)
        raise HTTPException(status_code=500, detail=f"Orchestrator test failed: {str(e)}")


@router.post("/run-daily-workflow", response_model=OrchestratorWorkflowResponse)
async def run_daily_workflow(
    tenant_id: str,
    request_data: Optional[OrchestratorWorkflowRequest] = None,
    request: Request = None,
    db: AsyncSession = Depends(get_db)
):
    """
    Trigger the daily orchestrated workflow for a tenant

    This endpoint runs the complete daily workflow which includes:
    1. Forecasting Service: Generate demand forecasts
    2. Production Service: Create production schedule from forecasts
    3. Procurement Service: Generate procurement plan
    4. Notification Service: Send relevant notifications

    This is the production endpoint used by the dashboard scheduler button.

    Args:
        tenant_id: Tenant ID to orchestrate
        request_data: Optional request data with dry_run flag
        request: FastAPI request object
        db: Database session

    Returns:
        OrchestratorWorkflowResponse with workflow execution results
    """
    logger.info("Daily workflow trigger requested", tenant_id=tenant_id)

    # Handle optional request_data
    if request_data is None:
        request_data = OrchestratorWorkflowRequest()

    try:
        # Get scheduler service from app state
        if not hasattr(request.app.state, 'scheduler_service'):
            raise HTTPException(
                status_code=503,
                detail="Orchestrator scheduler service not available"
            )

        scheduler_service = request.app.state.scheduler_service

        # Trigger orchestration (use full workflow, not test scenario)
        tenant_uuid = uuid.UUID(tenant_id)
        result = await scheduler_service.trigger_orchestration_for_tenant(
            tenant_id=tenant_uuid,
            test_scenario=None  # Full production workflow
        )

        # Get the latest run for this tenant
        repo = OrchestrationRunRepository(db)
        latest_run = await repo.get_latest_run_for_tenant(tenant_uuid)

        # Build response
        response = OrchestratorWorkflowResponse(
            success=result.get('success', False),
            message=result.get('message', 'Daily workflow completed successfully'),
            tenant_id=tenant_id,
            run_id=str(latest_run.id) if latest_run else None,
            forecasting_completed=latest_run.forecasting_status == 'success' if latest_run else False,
            production_completed=latest_run.production_status == 'success' if latest_run else False,
            procurement_completed=latest_run.procurement_status == 'success' if latest_run else False,
            notifications_sent=latest_run.notification_status == 'success' if latest_run else False,
            summary={
                'run_number': latest_run.run_number if latest_run else 0,
                'forecasts_generated': latest_run.forecasts_generated if latest_run else 0,
                'production_batches_created': latest_run.production_batches_created if latest_run else 0,
                'purchase_orders_created': latest_run.purchase_orders_created if latest_run else 0,
                'notifications_sent': latest_run.notifications_sent if latest_run else 0,
                'duration_seconds': latest_run.duration_seconds if latest_run else 0
            }
        )

        logger.info("Daily workflow completed",
                   tenant_id=tenant_id,
                   success=response.success,
                   run_id=response.run_id)

        return response

    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"Invalid tenant ID: {str(e)}")
    except Exception as e:
        logger.error("Daily workflow failed",
                    tenant_id=tenant_id,
                    error=str(e),
                    exc_info=True)
        raise HTTPException(status_code=500, detail=f"Daily workflow failed: {str(e)}")


@router.get("/health")
async def orchestrator_health():
    """Check orchestrator health"""
    return {
        "status": "healthy",
        "service": "orchestrator",
        "message": "Orchestrator service is running"
    }


@router.get("/runs", response_model=dict)
async def list_orchestration_runs(
    tenant_id: str,
    limit: int = 10,
    offset: int = 0,
    db: AsyncSession = Depends(get_db)
):
    """
    List orchestration runs for a tenant

    Args:
        tenant_id: Tenant ID
        limit: Maximum number of runs to return
        offset: Number of runs to skip
        db: Database session

    Returns:
        List of orchestration runs
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
        repo = OrchestrationRunRepository(db)

        runs = await repo.list_runs(
            tenant_id=tenant_uuid,
            limit=limit,
            offset=offset
        )

        return {
            "runs": [
                {
                    "id": str(run.id),
                    "run_number": run.run_number,
                    "status": run.status.value,
                    "started_at": run.started_at.isoformat() if run.started_at else None,
                    "completed_at": run.completed_at.isoformat() if run.completed_at else None,
                    "duration_seconds": run.duration_seconds,
                    "forecasts_generated": run.forecasts_generated,
                    "batches_created": run.production_batches_created,
                    "pos_created": run.purchase_orders_created
                }
                for run in runs
            ],
            "total": len(runs),
            "limit": limit,
            "offset": offset
        }

    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"Invalid tenant ID: {str(e)}")
    except Exception as e:
        logger.error("Error listing orchestration runs",
                    tenant_id=tenant_id,
                    error=str(e))
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/last-run")
async def get_last_orchestration_run(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Get timestamp of last orchestration run

    Lightweight endpoint for health status frontend migration (Phase 4).
    Returns only timestamp and run number for the most recent completed run.

    Args:
        tenant_id: Tenant ID

    Returns:
        Dict with timestamp and runNumber (or None if no runs)
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
        repo = OrchestrationRunRepository(db)

        # Get most recent completed run
        latest_run = await repo.get_latest_run_for_tenant(tenant_uuid)

        if not latest_run:
            return {"timestamp": None, "runNumber": None}

        return {
            "timestamp": latest_run.started_at.isoformat() if latest_run.started_at else None,
            "runNumber": latest_run.run_number
        }

    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"Invalid tenant ID: {str(e)}")
    except Exception as e:
        logger.error("Error getting last orchestration run",
                    tenant_id=tenant_id,
                    error=str(e))
        raise HTTPException(status_code=500, detail=str(e))
