# ================================================================
# services/procurement/app/api/procurement_plans.py
# ================================================================
"""
Procurement Plans API - Endpoints for procurement planning
"""

import uuid
from typing import List, Optional
from datetime import date
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
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,
    AutoGenerateProcurementRequest,
    AutoGenerateProcurementResponse,
    PaginatedProcurementPlans,
)
from shared.routing import RouteBuilder
import structlog

logger = structlog.get_logger()

# Create route builder for consistent URL structure
route_builder = RouteBuilder('procurement')
router = APIRouter(tags=["procurement-plans"])


def get_procurement_service(db: AsyncSession = Depends(get_db)) -> ProcurementService:
    """Dependency to get procurement service"""
    return ProcurementService(db, settings)


# ================================================================
# ORCHESTRATOR ENTRY POINT
# ================================================================

@router.post(
    route_builder.build_operations_route("auto-generate"),
    response_model=AutoGenerateProcurementResponse
)
async def auto_generate_procurement(
    request_data: AutoGenerateProcurementRequest,
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service),
    db: AsyncSession = Depends(get_db)
):
    """
    Auto-generate procurement plan from forecast data (called by Orchestrator)

    This is the main entry point for orchestrated procurement planning.
    The Orchestrator calls Forecasting Service first, then passes forecast data here.

    Flow:
    1. Receive forecast data from orchestrator
    2. Calculate procurement requirements
    3. Apply Recipe Explosion for locally-produced items
    4. Create procurement plan
    5. Optionally create and auto-approve purchase orders

    Returns:
        AutoGenerateProcurementResponse with plan details and created POs
    """
    try:
        logger.info("Auto-generate procurement endpoint called",
                   tenant_id=tenant_id,
                   has_forecast_data=bool(request_data.forecast_data))

        result = await service.auto_generate_procurement(
            tenant_id=uuid.UUID(tenant_id),
            request=request_data
        )

        return result

    except Exception as e:
        logger.error("Error in auto_generate_procurement endpoint", error=str(e), tenant_id=tenant_id)
        raise HTTPException(status_code=500, detail=str(e))


# ================================================================
# MANUAL PROCUREMENT PLAN GENERATION
# ================================================================

@router.post(
    route_builder.build_base_route("plans"),
    response_model=GeneratePlanResponse
)
async def generate_procurement_plan(
    request_data: GeneratePlanRequest,
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service)
):
    """
    Generate a new procurement plan (manual/UI-driven)

    This endpoint is used for manual procurement planning from the UI.
    Unlike auto_generate_procurement, this generates its own forecasts.

    Args:
        tenant_id: Tenant UUID
        request_data: Plan generation parameters

    Returns:
        GeneratePlanResponse with the created plan
    """
    try:
        logger.info("Generate procurement plan endpoint called",
                   tenant_id=tenant_id,
                   plan_date=request_data.plan_date)

        result = await service.generate_procurement_plan(
            tenant_id=uuid.UUID(tenant_id),
            request=request_data
        )

        return result

    except Exception as e:
        logger.error("Error generating procurement plan", error=str(e), tenant_id=tenant_id)
        raise HTTPException(status_code=500, detail=str(e))


# ================================================================
# PROCUREMENT PLAN CRUD
# ================================================================

@router.get(
    route_builder.build_base_route("plans/current"),
    response_model=Optional[ProcurementPlanResponse]
)
async def get_current_plan(
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service)
):
    """Get the current day's procurement plan"""
    try:
        plan = await service.get_current_plan(uuid.UUID(tenant_id))
        return plan

    except Exception as e:
        logger.error("Error getting current plan", error=str(e), tenant_id=tenant_id)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_resource_detail_route("plans", "plan_id"),
    response_model=ProcurementPlanResponse
)
async def get_plan_by_id(
    plan_id: str,
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service)
):
    """Get procurement plan by ID"""
    try:
        plan = await service.get_plan_by_id(uuid.UUID(tenant_id), uuid.UUID(plan_id))

        if not plan:
            raise HTTPException(status_code=404, detail="Plan not found")

        return plan

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting plan by ID", error=str(e), tenant_id=tenant_id, plan_id=plan_id)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_base_route("plans/date/{plan_date}"),
    response_model=Optional[ProcurementPlanResponse]
)
async def get_plan_by_date(
    plan_date: date,
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service)
):
    """Get procurement plan for a specific date"""
    try:
        plan = await service.get_plan_by_date(uuid.UUID(tenant_id), plan_date)
        return plan

    except Exception as e:
        logger.error("Error getting plan by date", error=str(e), tenant_id=tenant_id, plan_date=plan_date)
        raise HTTPException(status_code=500, detail=str(e))


@router.get(
    route_builder.build_base_route("plans"),
    response_model=PaginatedProcurementPlans
)
async def list_procurement_plans(
    tenant_id: str = Path(..., description="Tenant ID"),
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=50, ge=1, le=100),
    service: ProcurementService = Depends(get_procurement_service),
    db: AsyncSession = Depends(get_db)
):
    """List all procurement plans for tenant with pagination"""
    try:
        from app.repositories.procurement_plan_repository import ProcurementPlanRepository

        repo = ProcurementPlanRepository(db)
        plans = await repo.list_plans(uuid.UUID(tenant_id), skip=skip, limit=limit)
        total = await repo.count_plans(uuid.UUID(tenant_id))

        plans_response = [ProcurementPlanResponse.model_validate(p) for p in plans]

        return PaginatedProcurementPlans(
            plans=plans_response,
            total=total,
            page=skip // limit + 1,
            limit=limit,
            has_more=(skip + limit) < total
        )

    except Exception as e:
        logger.error("Error listing procurement plans", error=str(e), tenant_id=tenant_id)
        raise HTTPException(status_code=500, detail=str(e))


@router.patch(
    route_builder.build_resource_action_route("plans", "plan_id", "status")
)
async def update_plan_status(
    plan_id: str,
    status: str = Query(..., regex="^(draft|pending_approval|approved|in_execution|completed|cancelled)$"),
    tenant_id: str = Path(..., description="Tenant ID"),
    notes: Optional[str] = None,
    service: ProcurementService = Depends(get_procurement_service)
):
    """Update procurement plan status"""
    try:
        updated_plan = await service.update_plan_status(
            tenant_id=uuid.UUID(tenant_id),
            plan_id=uuid.UUID(plan_id),
            status=status,
            approval_notes=notes
        )

        if not updated_plan:
            raise HTTPException(status_code=404, detail="Plan not found")

        return updated_plan

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error updating plan status", error=str(e), tenant_id=tenant_id, plan_id=plan_id)
        raise HTTPException(status_code=500, detail=str(e))


@router.post(
    route_builder.build_resource_action_route("plans", "plan_id", "create-purchase-orders")
)
async def create_purchase_orders_from_plan(
    plan_id: str,
    auto_approve: bool = Query(default=False, description="Auto-approve qualifying purchase orders"),
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service)
):
    """
    Create purchase orders from procurement plan requirements

    Groups requirements by supplier and creates POs automatically.
    Optionally evaluates auto-approval rules for qualifying POs.

    Args:
        tenant_id: Tenant UUID
        plan_id: Procurement plan UUID
        auto_approve: Whether to auto-approve qualifying POs

    Returns:
        Summary of created, approved, and failed purchase orders
    """
    try:
        result = await service.create_purchase_orders_from_plan(
            tenant_id=uuid.UUID(tenant_id),
            plan_id=uuid.UUID(plan_id),
            auto_approve=auto_approve
        )

        if not result.get('success'):
            raise HTTPException(status_code=400, detail=result.get('error', 'Failed to create purchase orders'))

        return result

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error creating POs from plan", error=str(e), tenant_id=tenant_id, plan_id=plan_id)
        raise HTTPException(status_code=500, detail=str(e))


# ================================================================
# TESTING AND UTILITIES
# ================================================================

@router.get(
    route_builder.build_resource_action_route("plans", "plan_id", "requirements")
)
async def get_plan_requirements(
    plan_id: str,
    tenant_id: str = Path(..., description="Tenant ID"),
    service: ProcurementService = Depends(get_procurement_service),
    db: AsyncSession = Depends(get_db)
):
    """Get all requirements for a procurement plan"""
    try:
        from app.repositories.procurement_plan_repository import ProcurementRequirementRepository

        repo = ProcurementRequirementRepository(db)
        requirements = await repo.get_requirements_by_plan(uuid.UUID(plan_id))

        return {
            "plan_id": plan_id,
            "requirements_count": len(requirements),
            "requirements": [
                {
                    "id": str(req.id),
                    "requirement_number": req.requirement_number,
                    "product_name": req.product_name,
                    "net_requirement": float(req.net_requirement),
                    "unit_of_measure": req.unit_of_measure,
                    "priority": req.priority,
                    "status": req.status,
                    "is_locally_produced": req.is_locally_produced,
                    "bom_explosion_level": req.bom_explosion_level,
                    "supplier_name": req.supplier_name,
                    "estimated_total_cost": float(req.estimated_total_cost or 0)
                }
                for req in requirements
            ]
        }

    except Exception as e:
        logger.error("Error getting plan requirements", error=str(e), tenant_id=tenant_id, plan_id=plan_id)
        raise HTTPException(status_code=500, detail=str(e))
