"""
Procurement Service - ENHANCED VERSION
Integrates advanced replenishment planning with:
- Lead-time-aware planning
- Dynamic safety stock
- Inventory projection
- Shelf-life management
- MOQ optimization
- Multi-criteria supplier selection

This is a COMPLETE REWRITE integrating all new planning services.
"""

import asyncio
import uuid
from datetime import datetime, date, timedelta
from decimal import Decimal
from typing import List, Optional, Dict, Any, Tuple
import structlog
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.procurement_plan import ProcurementPlan, ProcurementRequirement
from app.models.replenishment import ReplenishmentPlan, ReplenishmentPlanItem
from app.repositories.procurement_plan_repository import ProcurementPlanRepository, ProcurementRequirementRepository
from app.schemas.procurement_schemas import (
    AutoGenerateProcurementRequest, AutoGenerateProcurementResponse
)
from app.core.config import settings
from shared.clients.inventory_client import InventoryServiceClient
from shared.clients.forecast_client import ForecastServiceClient
from shared.clients.suppliers_client import SuppliersServiceClient
from shared.clients.recipes_client import RecipesServiceClient
from shared.config.base import BaseServiceSettings
from shared.messaging import RabbitMQClient
from shared.monitoring.decorators import monitor_performance
from shared.utils.tenant_settings_client import TenantSettingsClient

# NEW: Import all planning services
from app.services.replenishment_planning_service import (
    ReplenishmentPlanningService,
    IngredientRequirement
)
from app.services.moq_aggregator import (
    MOQAggregator,
    ProcurementRequirement as MOQProcurementRequirement,
    SupplierConstraints
)
from app.services.supplier_selector import (
    SupplierSelector,
    SupplierOption
)
from app.services.recipe_explosion_service import RecipeExplosionService
from app.services.smart_procurement_calculator import SmartProcurementCalculator

logger = structlog.get_logger()


class ProcurementService:
    """
    Enhanced Procurement Service with Advanced Planning

    NEW WORKFLOW:
    1. Generate forecast (from Orchestrator)
    2. Get current inventory
    3. Build ingredient requirements
    4. Generate replenishment plan (NEW - with all planning algorithms)
    5. Apply MOQ aggregation (NEW)
    6. Select suppliers (NEW - multi-criteria)
    7. Create purchase orders
    8. Save everything to database
    """

    def __init__(
        self,
        db: AsyncSession,
        config: BaseServiceSettings,
        inventory_client: Optional[InventoryServiceClient] = None,
        forecast_client: Optional[ForecastServiceClient] = None,
        suppliers_client: Optional[SuppliersServiceClient] = None,
        recipes_client: Optional[RecipesServiceClient] = None,
    ):
        self.db = db
        self.config = config
        self.plan_repo = ProcurementPlanRepository(db)
        self.requirement_repo = ProcurementRequirementRepository(db)

        # Initialize service clients
        self.inventory_client = inventory_client or InventoryServiceClient(config)
        self.forecast_client = forecast_client or ForecastServiceClient(config, "procurement-service")
        self.suppliers_client = suppliers_client or SuppliersServiceClient(config)
        self.recipes_client = recipes_client or RecipesServiceClient(config)

        # Initialize tenant settings client
        tenant_service_url = getattr(config, 'TENANT_SERVICE_URL', 'http://tenant-service:8000')
        self.tenant_settings_client = TenantSettingsClient(tenant_service_url=tenant_service_url)

        # Initialize RabbitMQ client
        rabbitmq_url = getattr(config, 'RABBITMQ_URL', 'amqp://guest:guest@localhost:5672/')
        self.rabbitmq_client = RabbitMQClient(rabbitmq_url, "procurement-service")

        # Initialize Recipe Explosion Service
        self.recipe_explosion_service = RecipeExplosionService(
            recipes_client=self.recipes_client,
            inventory_client=self.inventory_client
        )

        # Initialize Smart Calculator (keep for backward compatibility)
        self.smart_calculator = SmartProcurementCalculator(
            procurement_settings={
                'use_reorder_rules': True,
                'economic_rounding': True,
                'respect_storage_limits': True,
                'use_supplier_minimums': True,
                'optimize_price_tiers': True
            }
        )

        # NEW: Initialize advanced planning services
        self.replenishment_planner = ReplenishmentPlanningService(
            projection_horizon_days=getattr(settings, 'REPLENISHMENT_PROJECTION_HORIZON_DAYS', 7),
            default_service_level=getattr(settings, 'REPLENISHMENT_SERVICE_LEVEL', 0.95),
            default_buffer_days=getattr(settings, 'REPLENISHMENT_BUFFER_DAYS', 1)
        )

        self.moq_aggregator = MOQAggregator(
            consolidation_window_days=getattr(settings, 'MOQ_CONSOLIDATION_WINDOW_DAYS', 7),
            allow_early_ordering=getattr(settings, 'MOQ_ALLOW_EARLY_ORDERING', True)
        )

        self.supplier_selector = SupplierSelector(
            price_weight=getattr(settings, 'SUPPLIER_PRICE_WEIGHT', 0.40),
            lead_time_weight=getattr(settings, 'SUPPLIER_LEAD_TIME_WEIGHT', 0.20),
            quality_weight=getattr(settings, 'SUPPLIER_QUALITY_WEIGHT', 0.20),
            reliability_weight=getattr(settings, 'SUPPLIER_RELIABILITY_WEIGHT', 0.20),
            diversification_threshold=getattr(settings, 'SUPPLIER_DIVERSIFICATION_THRESHOLD', Decimal('1000')),
            max_single_supplier_percentage=getattr(settings, 'SUPPLIER_MAX_SINGLE_PERCENTAGE', 0.70)
        )

        logger.info("ProcurementServiceEnhanced initialized with advanced planning")

    @monitor_performance("auto_generate_procurement_enhanced")
    async def auto_generate_procurement(
        self,
        tenant_id: uuid.UUID,
        request: AutoGenerateProcurementRequest
    ) -> AutoGenerateProcurementResponse:
        """
        Auto-generate procurement plan with ADVANCED PLANNING

        NEW WORKFLOW (vs old):
        OLD: Forecast → Simple stock check → Create POs
        NEW: Forecast → Replenishment Planning → MOQ Optimization → Supplier Selection → Create POs
        """
        try:
            target_date = request.target_date or date.today()
            forecast_data = request.forecast_data

            logger.info("Starting ENHANCED auto-generate procurement",
                       tenant_id=tenant_id,
                       target_date=target_date,
                       has_forecast_data=bool(forecast_data))

            # ============================================================
            # STEP 1: Get Current Inventory (Use cached if available)
            # ============================================================
            if request.inventory_data:
                # Use cached inventory from Orchestrator (NEW)
                inventory_items = request.inventory_data.get('ingredients', [])
                logger.info(f"Using cached inventory snapshot: {len(inventory_items)} items")
            else:
                # Fallback: Fetch from Inventory Service
                inventory_items = await self._get_inventory_list(tenant_id)
                logger.info(f"Fetched inventory from service: {len(inventory_items)} items")

            if not inventory_items:
                return AutoGenerateProcurementResponse(
                    success=False,
                    message="No inventory items found",
                    errors=["Unable to retrieve inventory data"]
                )

            # ============================================================
            # STEP 2: Get All Suppliers (Use cached if available)
            # ============================================================
            if request.suppliers_data:
                # Use cached suppliers from Orchestrator (NEW)
                suppliers = request.suppliers_data.get('suppliers', [])
                logger.info(f"Using cached suppliers snapshot: {len(suppliers)} suppliers")
            else:
                # Fallback: Fetch from Suppliers Service
                suppliers = await self._get_all_suppliers(tenant_id)
                logger.info(f"Fetched suppliers from service: {len(suppliers)} suppliers")

            # ============================================================
            # STEP 3: Parse Forecast Data
            # ============================================================
            forecasts = self._parse_forecast_data(forecast_data, inventory_items)
            logger.info(f"Parsed {len(forecasts)} forecast items")

            # ============================================================
            # STEP 4: Build Ingredient Requirements
            # ============================================================
            ingredient_requirements = await self._build_ingredient_requirements(
                tenant_id=tenant_id,
                forecasts=forecasts,
                inventory_items=inventory_items,
                suppliers=suppliers,
                target_date=target_date
            )

            if not ingredient_requirements:
                logger.warning("No ingredient requirements generated")
                return AutoGenerateProcurementResponse(
                    success=False,
                    message="No procurement requirements identified",
                    errors=["No items need replenishment"]
                )

            logger.info(f"Built {len(ingredient_requirements)} ingredient requirements")

            # ============================================================
            # STEP 5: Generate Replenishment Plan (NEW!)
            # ============================================================
            replenishment_plan = await self.replenishment_planner.generate_replenishment_plan(
                tenant_id=str(tenant_id),
                requirements=ingredient_requirements,
                forecast_id=forecast_data.get('forecast_id'),
                production_schedule_id=request.production_schedule_id
            )

            logger.info(
                f"Replenishment plan generated: {replenishment_plan.total_items} items, "
                f"{replenishment_plan.urgent_items} urgent, "
                f"{replenishment_plan.high_risk_items} high risk"
            )

            # ============================================================
            # STEP 6: Apply MOQ Aggregation (NEW!)
            # ============================================================
            moq_requirements, supplier_constraints = self._prepare_moq_inputs(
                replenishment_plan,
                suppliers
            )

            aggregated_orders = self.moq_aggregator.aggregate_requirements(
                requirements=moq_requirements,
                supplier_constraints=supplier_constraints
            )

            moq_efficiency = self.moq_aggregator.calculate_order_efficiency(aggregated_orders)
            logger.info(
                f"MOQ aggregation: {len(aggregated_orders)} aggregated orders from "
                f"{len(moq_requirements)} requirements "
                f"(consolidation ratio: {moq_efficiency['consolidation_ratio']:.2f})"
            )

            # ============================================================
            # STEP 7: Multi-Criteria Supplier Selection (NEW!)
            # ============================================================
            supplier_selections = await self._select_suppliers_for_requirements(
                replenishment_plan,
                suppliers
            )

            logger.info(f"Supplier selection completed for {len(supplier_selections)} items")

            # ============================================================
            # STEP 8: Save to Database
            # ============================================================
            # Create traditional procurement plan
            plan_data = {
                'tenant_id': tenant_id,
                'plan_number': await self._generate_plan_number(),
                'plan_date': target_date,
                'planning_horizon_days': request.planning_horizon_days,
                'status': 'draft',
                'forecast_id': forecast_data.get('forecast_id'),
                'production_schedule_id': request.production_schedule_id,
                'total_estimated_cost': replenishment_plan.total_estimated_cost,
                'seasonality_adjustment': Decimal('1.0')
            }

            plan = await self.plan_repo.create_plan(plan_data)

            # Create procurement requirements from replenishment plan
            requirements_data = self._convert_replenishment_to_requirements(
                plan_id=plan.id,
                tenant_id=tenant_id,
                replenishment_plan=replenishment_plan,
                supplier_selections=supplier_selections
            )

            # Save requirements
            created_requirements = await self.requirement_repo.create_requirements_batch(requirements_data)

            # Update plan totals
            await self.plan_repo.update_plan(plan.id, tenant_id, {
                'total_requirements': len(requirements_data),
                'primary_suppliers_count': len(set(
                    r.get('preferred_supplier_id') for r in requirements_data
                    if r.get('preferred_supplier_id')
                )),
                'supplier_diversification_score': moq_efficiency.get('consolidation_ratio', 1.0)
            })

            # ============================================================
            # STEP 9: Optionally Create Purchase Orders
            # ============================================================
            created_pos = []
            if request.auto_create_pos:
                po_result = await self._create_purchase_orders_from_plan(
                    tenant_id=tenant_id,
                    plan_id=plan.id,
                    auto_approve=request.auto_approve_pos
                )
                if po_result.get('success'):
                    created_pos = po_result.get('created_pos', [])

            await self.db.commit()

            # ============================================================
            # STEP 10: Publish Events
            # ============================================================
            await self._publish_plan_generated_event(tenant_id, plan.id)

            logger.info(
                "ENHANCED procurement plan completed successfully",
                tenant_id=tenant_id,
                plan_id=plan.id,
                requirements_count=len(requirements_data),
                pos_created=len(created_pos),
                urgent_items=replenishment_plan.urgent_items,
                high_risk_items=replenishment_plan.high_risk_items
            )

            return AutoGenerateProcurementResponse(
                success=True,
                message="Enhanced procurement plan generated successfully",
                plan_id=plan.id,
                plan_number=plan.plan_number,
                requirements_created=len(requirements_data),
                purchase_orders_created=len(created_pos),
                purchase_orders_auto_approved=sum(1 for po in created_pos if po.get('auto_approved')),
                total_estimated_cost=replenishment_plan.total_estimated_cost,
                created_pos=created_pos
            )

        except Exception as e:
            await self.db.rollback()
            logger.error("Error in enhanced auto_generate_procurement",
                        error=str(e), tenant_id=tenant_id, exc_info=True)
            return AutoGenerateProcurementResponse(
                success=False,
                message="Failed to generate enhanced procurement plan",
                errors=[str(e)]
            )

    async def get_procurement_analytics(self, tenant_id: uuid.UUID, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None):
        """
        Get procurement analytics dashboard data with real supplier data and trends
        """
        try:
            logger.info("Retrieving procurement analytics", tenant_id=tenant_id)

            # Set default date range if not provided
            if not end_date:
                end_date = datetime.now()
            if not start_date:
                start_date = end_date - timedelta(days=30)

            # Get procurement plans summary
            plans = await self.plan_repo.get_plans_by_tenant(tenant_id, start_date, end_date)
            total_plans = len(plans)

            # Calculate summary metrics
            total_estimated_cost = sum(float(plan.total_estimated_cost or 0) for plan in plans)
            total_approved_cost = sum(float(plan.total_approved_cost or 0) for plan in plans)
            cost_variance = total_approved_cost - total_estimated_cost

            # Get requirements for performance metrics
            requirements = await self.requirement_repo.get_requirements_by_tenant(tenant_id, start_date, end_date)

            # Calculate performance metrics
            fulfilled_requirements = [r for r in requirements if r.status == 'received']
            on_time_deliveries = [r for r in fulfilled_requirements if r.delivery_status == 'delivered']

            fulfillment_rate = len(fulfilled_requirements) / len(requirements) if requirements else 0
            on_time_rate = len(on_time_deliveries) / len(fulfilled_requirements) if fulfilled_requirements else 0

            # Calculate cost accuracy
            cost_accuracy = 0
            if requirements:
                cost_variance_items = [r for r in requirements if r.estimated_total_cost and r.estimated_total_cost != 0]
                if cost_variance_items:
                    cost_accuracy = 1.0 - (sum(
                        abs(float(r.estimated_total_cost or 0) - float(r.approved_cost or 0)) / float(r.estimated_total_cost or 1)
                        for r in cost_variance_items
                    ) / len(cost_variance_items))

            # ============================================================
            # TREND CALCULATIONS (7-day comparison)
            # ============================================================
            trend_start = end_date - timedelta(days=7)
            previous_period_end = trend_start
            previous_period_start = previous_period_end - timedelta(days=7)

            # Get previous period data
            prev_requirements = await self.requirement_repo.get_requirements_by_tenant(
                tenant_id, previous_period_start, previous_period_end
            )

            # Calculate previous period metrics
            prev_fulfilled = [r for r in prev_requirements if r.status == 'received']
            prev_on_time = [r for r in prev_fulfilled if r.delivery_status == 'delivered']

            prev_fulfillment_rate = len(prev_fulfilled) / len(prev_requirements) if prev_requirements else 0
            prev_on_time_rate = len(prev_on_time) / len(prev_fulfilled) if prev_fulfilled else 0

            prev_cost_accuracy = 0
            if prev_requirements:
                prev_cost_items = [r for r in prev_requirements if r.estimated_total_cost and r.estimated_total_cost != 0]
                if prev_cost_items:
                    prev_cost_accuracy = 1.0 - (sum(
                        abs(float(r.estimated_total_cost or 0) - float(r.approved_cost or 0)) / float(r.estimated_total_cost or 1)
                        for r in prev_cost_items
                    ) / len(prev_cost_items))

            # Calculate trend percentages
            fulfillment_trend = self._calculate_trend_percentage(fulfillment_rate, prev_fulfillment_rate)
            on_time_trend = self._calculate_trend_percentage(on_time_rate, prev_on_time_rate)
            cost_variance_trend = self._calculate_trend_percentage(cost_accuracy, prev_cost_accuracy)

            # Plan status distribution
            status_counts = {}
            for plan in plans:
                status = plan.status
                status_counts[status] = status_counts.get(status, 0) + 1

            plan_status_distribution = [
                {"status": status, "count": count}
                for status, count in status_counts.items()
            ]

            # ============================================================
            # CRITICAL REQUIREMENTS with REAL INVENTORY DATA
            # ============================================================
            try:
                inventory_items = await self.inventory_client.get_all_ingredients(str(tenant_id))
                inventory_map = {str(item.get('id')): item for item in inventory_items}

                low_stock_count = 0
                for req in requirements:
                    ingredient_id = str(req.ingredient_id)
                    if ingredient_id in inventory_map:
                        inv_item = inventory_map[ingredient_id]
                        current_stock = float(inv_item.get('quantity_available', 0))
                        reorder_point = float(inv_item.get('reorder_point', 0))
                        if current_stock <= reorder_point:
                            low_stock_count += 1
            except Exception as e:
                logger.warning("Failed to get inventory data for critical requirements", error=str(e))
                low_stock_count = len([r for r in requirements if r.priority == 'high'])

            critical_requirements = {
                "low_stock": low_stock_count,
                "overdue": len([r for r in requirements if r.status == 'pending' and r.required_by_date < datetime.now().date()]),
                "high_priority": len([r for r in requirements if r.priority == 'high'])
            }

            # Recent plans
            recent_plans = []
            for plan in sorted(plans, key=lambda x: x.created_at, reverse=True)[:5]:
                recent_plans.append({
                    "id": str(plan.id),
                    "plan_number": plan.plan_number,
                    "plan_date": plan.plan_date.isoformat() if plan.plan_date else None,
                    "status": plan.status,
                    "total_requirements": plan.total_requirements or 0,
                    "total_estimated_cost": float(plan.total_estimated_cost or 0),
                    "created_at": plan.created_at.isoformat() if plan.created_at else None
                })

            # ============================================================
            # SUPPLIER PERFORMANCE with REAL SUPPLIER DATA
            # ============================================================
            supplier_performance = []
            supplier_reqs = {}
            for req in requirements:
                if req.preferred_supplier_id:
                    supplier_id = str(req.preferred_supplier_id)
                    if supplier_id not in supplier_reqs:
                        supplier_reqs[supplier_id] = []
                    supplier_reqs[supplier_id].append(req)

            # Fetch real supplier data
            try:
                suppliers_data = await self.suppliers_client.get_all_suppliers(str(tenant_id))
                suppliers_map = {str(s.get('id')): s for s in suppliers_data}

                for supplier_id, reqs in supplier_reqs.items():
                    fulfilled = len([r for r in reqs if r.status == 'received'])
                    on_time = len([r for r in reqs if r.delivery_status == 'delivered'])

                    # Get real supplier info
                    supplier_info = suppliers_map.get(supplier_id, {})
                    supplier_name = supplier_info.get('name', f'Unknown Supplier')

                    # Use real quality rating from supplier data
                    quality_score = supplier_info.get('quality_rating', 0)
                    delivery_rating = supplier_info.get('delivery_rating', 0)

                    supplier_performance.append({
                        "id": supplier_id,
                        "name": supplier_name,
                        "total_orders": len(reqs),
                        "fulfillment_rate": fulfilled / len(reqs) if reqs else 0,
                        "on_time_rate": on_time / fulfilled if fulfilled else 0,
                        "quality_score": quality_score
                    })
            except Exception as e:
                logger.warning("Failed to get supplier data, using fallback", error=str(e))
                for supplier_id, reqs in supplier_reqs.items():
                    fulfilled = len([r for r in reqs if r.status == 'received'])
                    on_time = len([r for r in reqs if r.delivery_status == 'delivered'])
                    supplier_performance.append({
                        "id": supplier_id,
                        "name": f"Supplier {supplier_id[:8]}...",
                        "total_orders": len(reqs),
                        "fulfillment_rate": fulfilled / len(reqs) if reqs else 0,
                        "on_time_rate": on_time / fulfilled if fulfilled else 0,
                        "quality_score": 0
                    })

            # Cost by category
            cost_by_category = []
            category_costs = {}
            for req in requirements:
                category = req.product_category or "Uncategorized"
                category_costs[category] = category_costs.get(category, 0) + float(req.estimated_total_cost or 0)

            for category, amount in category_costs.items():
                cost_by_category.append({
                    "name": category,
                    "amount": amount
                })

            # Quality metrics
            quality_reqs = [r for r in requirements if hasattr(r, 'quality_rating') and r.quality_rating]
            avg_quality = sum(r.quality_rating for r in quality_reqs) / len(quality_reqs) if quality_reqs else 0
            high_quality_count = len([r for r in quality_reqs if r.quality_rating >= 4.0])
            low_quality_count = len([r for r in quality_reqs if r.quality_rating <= 2.0])

            analytics_data = {
                "summary": {
                    "total_plans": total_plans,
                    "total_estimated_cost": total_estimated_cost,
                    "total_approved_cost": total_approved_cost,
                    "cost_variance": cost_variance
                },
                "performance_metrics": {
                    "average_fulfillment_rate": fulfillment_rate,
                    "average_on_time_delivery": on_time_rate,
                    "cost_accuracy": cost_accuracy,
                    "supplier_performance": avg_quality if quality_reqs else 0,
                    "fulfillment_trend": fulfillment_trend,
                    "on_time_trend": on_time_trend,
                    "cost_variance_trend": cost_variance_trend
                },
                "plan_status_distribution": plan_status_distribution,
                "critical_requirements": critical_requirements,
                "recent_plans": recent_plans,
                "supplier_performance": supplier_performance,
                "cost_by_category": cost_by_category,
                "quality_metrics": {
                    "avg_score": avg_quality,
                    "high_quality_count": high_quality_count,
                    "low_quality_count": low_quality_count
                }
            }

            return analytics_data

        except Exception as e:
            logger.error("Failed to get procurement analytics", error=str(e), tenant_id=tenant_id)
            raise

    def _calculate_trend_percentage(self, current_value: float, previous_value: float) -> float:
        """
        Calculate percentage change between current and previous values
        Returns percentage change (e.g., 0.05 for 5% increase, -0.03 for 3% decrease)
        """
        if previous_value == 0:
            return 0.0 if current_value == 0 else 1.0

        change = ((current_value - previous_value) / previous_value)
        return round(change, 4)

    async def get_procurement_trends(self, tenant_id: uuid.UUID, days: int = 7):
        """
        Get time-series procurement trends for charts (last N days)
        Returns daily metrics for performance and quality trends
        """
        try:
            logger.info("Retrieving procurement trends", tenant_id=tenant_id, days=days)

            end_date = datetime.now()
            start_date = end_date - timedelta(days=days)

            # Get requirements for the period
            requirements = await self.requirement_repo.get_requirements_by_tenant(tenant_id, start_date, end_date)

            # Group requirements by day
            daily_data = {}
            for day_offset in range(days):
                day_date = (start_date + timedelta(days=day_offset)).date()
                daily_data[day_date] = {
                    'date': day_date.isoformat(),
                    'requirements': [],
                    'fulfillment_rate': 0,
                    'on_time_rate': 0,
                    'quality_score': 0
                }

            # Assign requirements to days based on creation date
            for req in requirements:
                req_date = req.created_at.date() if req.created_at else None
                if req_date and req_date in daily_data:
                    daily_data[req_date]['requirements'].append(req)

            # Calculate daily metrics
            performance_trend = []
            quality_trend = []

            for day_date in sorted(daily_data.keys()):
                day_reqs = daily_data[day_date]['requirements']

                if day_reqs:
                    # Calculate fulfillment rate
                    fulfilled = [r for r in day_reqs if r.status == 'received']
                    fulfillment_rate = len(fulfilled) / len(day_reqs) if day_reqs else 0

                    # Calculate on-time rate
                    on_time = [r for r in fulfilled if r.delivery_status == 'delivered']
                    on_time_rate = len(on_time) / len(fulfilled) if fulfilled else 0

                    # Calculate quality score
                    quality_reqs = [r for r in day_reqs if hasattr(r, 'quality_rating') and r.quality_rating]
                    avg_quality = sum(r.quality_rating for r in quality_reqs) / len(quality_reqs) if quality_reqs else 0
                else:
                    fulfillment_rate = 0
                    on_time_rate = 0
                    avg_quality = 0

                performance_trend.append({
                    'date': day_date.isoformat(),
                    'fulfillment_rate': round(fulfillment_rate, 4),
                    'on_time_rate': round(on_time_rate, 4)
                })

                quality_trend.append({
                    'date': day_date.isoformat(),
                    'quality_score': round(avg_quality, 2)
                })

            return {
                'performance_trend': performance_trend,
                'quality_trend': quality_trend,
                'period_days': days,
                'start_date': start_date.date().isoformat(),
                'end_date': end_date.date().isoformat()
            }

        except Exception as e:
            logger.error("Failed to get procurement trends", error=str(e), tenant_id=tenant_id)
            raise

    # ============================================================
    # Helper Methods
    # ============================================================

    async def _build_ingredient_requirements(
        self,
        tenant_id: uuid.UUID,
        forecasts: List[Dict],
        inventory_items: List[Dict],
        suppliers: List[Dict],
        target_date: date
    ) -> List[IngredientRequirement]:
        """
        Build ingredient requirements from forecasts
        """
        requirements = []

        for forecast in forecasts:
            ingredient_id = forecast.get('ingredient_id')
            ingredient = next((i for i in inventory_items if str(i['id']) == str(ingredient_id)), None)

            if not ingredient:
                continue

            # Calculate required quantity
            predicted_demand = Decimal(str(forecast.get('predicted_demand', 0)))
            current_stock = Decimal(str(ingredient.get('quantity', 0)))

            if predicted_demand > current_stock:
                required_quantity = predicted_demand - current_stock

                # Find preferred supplier
                preferred_supplier = self._find_preferred_supplier(ingredient, suppliers)

                # Get lead time
                lead_time_days = preferred_supplier.get('lead_time_days', 3) if preferred_supplier else 3

                # Build requirement
                req = IngredientRequirement(
                    ingredient_id=str(ingredient_id),
                    ingredient_name=ingredient.get('name', 'Unknown'),
                    required_quantity=required_quantity,
                    required_by_date=target_date + timedelta(days=7),
                    supplier_id=str(preferred_supplier['id']) if preferred_supplier else None,
                    lead_time_days=lead_time_days,
                    shelf_life_days=ingredient.get('shelf_life_days'),
                    is_perishable=ingredient.get('category') in ['fresh', 'dairy', 'produce'],
                    category=ingredient.get('category', 'dry'),
                    unit_of_measure=ingredient.get('unit_of_measure', 'kg'),
                    current_stock=current_stock,
                    daily_consumption_rate=float(predicted_demand) / 7,  # Estimate
                    demand_std_dev=float(forecast.get('confidence_score', 0)) * 10  # Rough estimate
                )

                requirements.append(req)

        return requirements

    def _prepare_moq_inputs(
        self,
        replenishment_plan,
        suppliers: List[Dict]
    ) -> Tuple[List[MOQProcurementRequirement], Dict[str, SupplierConstraints]]:
        """
        Prepare inputs for MOQ aggregator
        """
        moq_requirements = []
        supplier_constraints = {}

        for item in replenishment_plan.items:
            req = MOQProcurementRequirement(
                id=str(item.id),
                ingredient_id=item.ingredient_id,
                ingredient_name=item.ingredient_name,
                quantity=item.final_order_quantity,
                required_date=item.required_by_date,
                supplier_id=item.supplier_id or 'unknown',
                unit_of_measure=item.unit_of_measure
            )
            moq_requirements.append(req)

        # Build supplier constraints
        for supplier in suppliers:
            supplier_id = str(supplier['id'])
            supplier_constraints[supplier_id] = SupplierConstraints(
                supplier_id=supplier_id,
                supplier_name=supplier.get('name', 'Unknown'),
                min_order_quantity=Decimal(str(supplier.get('min_order_quantity', 0))) if supplier.get('min_order_quantity') else None,
                min_order_value=Decimal(str(supplier.get('min_order_value', 0))) if supplier.get('min_order_value') else None,
                package_size=None,  # Not in current schema
                max_order_quantity=None  # Not in current schema
            )

        return moq_requirements, supplier_constraints

    async def _select_suppliers_for_requirements(
        self,
        replenishment_plan,
        suppliers: List[Dict]
    ) -> Dict[str, Any]:
        """
        Select best suppliers for each requirement
        """
        selections = {}

        for item in replenishment_plan.items:
            # Build supplier options
            supplier_options = []
            for supplier in suppliers:
                option = SupplierOption(
                    supplier_id=str(supplier['id']),
                    supplier_name=supplier.get('name', 'Unknown'),
                    unit_price=Decimal(str(supplier.get('unit_price', 10))),  # Default price
                    lead_time_days=supplier.get('lead_time_days', 3),
                    min_order_quantity=Decimal(str(supplier.get('min_order_quantity', 0))) if supplier.get('min_order_quantity') else None,
                    quality_score=0.85,  # Default quality
                    reliability_score=0.90  # Default reliability
                )
                supplier_options.append(option)

            if supplier_options:
                # Select suppliers
                result = self.supplier_selector.select_suppliers(
                    ingredient_id=item.ingredient_id,
                    ingredient_name=item.ingredient_name,
                    required_quantity=item.final_order_quantity,
                    supplier_options=supplier_options
                )

                selections[item.ingredient_id] = result

        return selections

    def _convert_replenishment_to_requirements(
        self,
        plan_id: uuid.UUID,
        tenant_id: uuid.UUID,
        replenishment_plan,
        supplier_selections: Dict
    ) -> List[Dict]:
        """
        Convert replenishment plan items to procurement requirements
        """
        requirements_data = []

        for item in replenishment_plan.items:
            # Get supplier selection
            selection = supplier_selections.get(item.ingredient_id)
            primary_allocation = selection.allocations[0] if selection and selection.allocations else None

            req_data = {
                'procurement_plan_id': plan_id,
                'tenant_id': tenant_id,
                'ingredient_id': uuid.UUID(item.ingredient_id),
                'ingredient_name': item.ingredient_name,
                'required_quantity': item.final_order_quantity,
                'unit_of_measure': item.unit_of_measure,
                'estimated_unit_price': primary_allocation.unit_price if primary_allocation else Decimal('10'),
                'estimated_total_cost': primary_allocation.total_cost if primary_allocation else item.final_order_quantity * Decimal('10'),
                'required_by_date': item.required_by_date,
                'priority': 'urgent' if item.is_urgent else 'normal',
                'preferred_supplier_id': uuid.UUID(primary_allocation.supplier_id) if primary_allocation else None,
                'calculation_method': 'ENHANCED_REPLENISHMENT_PLANNING',
                'ai_suggested_quantity': item.base_quantity,
                'adjusted_quantity': item.final_order_quantity,
                'adjustment_reason': f"Safety stock: {item.safety_stock_quantity}, Shelf-life adjusted",
                'lead_time_days': item.lead_time_days
            }

            requirements_data.append(req_data)

        return requirements_data

    # Additional helper methods (shortened for brevity)
    async def _get_inventory_list(self, tenant_id):
        """Get inventory items"""
        return await self.inventory_client.get_ingredients(str(tenant_id))

    async def _get_all_suppliers(self, tenant_id):
        """Get all suppliers"""
        return await self.suppliers_client.get_suppliers(str(tenant_id))

    def _parse_forecast_data(self, forecast_data, inventory_items):
        """Parse forecast data from orchestrator"""
        forecasts = forecast_data.get('forecasts', [])
        return forecasts

    def _find_preferred_supplier(self, ingredient, suppliers):
        """Find preferred supplier for ingredient"""
        # Simple: return first supplier (can be enhanced with logic)
        return suppliers[0] if suppliers else None

    async def _generate_plan_number(self):
        """Generate unique plan number"""
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        return f"PLAN-{timestamp}"

    async def _create_purchase_orders_from_plan(self, tenant_id, plan_id, auto_approve):
        """
        Create purchase orders from procurement plan requirements

        Groups requirements by supplier and creates POs with reasoning data
        """
        try:
            from shared.schemas.reasoning_types import create_po_reasoning_low_stock, create_po_reasoning_forecast_demand
            from collections import defaultdict

            # Get plan requirements
            requirements = await self.requirement_repo.get_requirements_by_plan(plan_id, tenant_id)

            if not requirements:
                logger.warning(f"No requirements found for plan {plan_id}")
                return {'success': False, 'created_pos': [], 'error': 'No requirements found'}

            # Group requirements by supplier
            supplier_requirements = defaultdict(list)
            for req in requirements:
                supplier_id = req.preferred_supplier_id
                if supplier_id:
                    supplier_requirements[supplier_id].append(req)

            created_pos = []

            # Create a PO for each supplier
            for supplier_id, reqs in supplier_requirements.items():
                try:
                    # Get supplier info
                    supplier = await self._get_supplier_by_id(tenant_id, supplier_id)
                    supplier_name = supplier.get('name', 'Unknown Supplier') if supplier else 'Unknown Supplier'

                    # Calculate PO totals
                    subtotal = sum(
                        (req.estimated_unit_cost or 0) * (req.net_requirement or 0)
                        for req in reqs
                    )

                    # Determine earliest required delivery date
                    required_delivery_date = min(req.required_by_date for req in reqs)

                    # Calculate urgency based on delivery date
                    days_until_delivery = (required_delivery_date - date.today()).days

                    # Collect product names for reasoning
                    product_names = [req.product_name for req in reqs[:3]]  # First 3 products
                    if len(reqs) > 3:
                        product_names.append(f"and {len(reqs) - 3} more")

                    # Determine reasoning type based on requirements
                    # If any requirement has low stock, use low_stock_detection
                    has_low_stock = any(
                        (req.current_stock_level or 0) < (req.total_quantity_needed or 0) * 0.3
                        for req in reqs
                    )

                    if has_low_stock:
                        # Calculate aggregate stock data for reasoning
                        total_current = sum(req.current_stock_level or 0 for req in reqs)
                        total_required = sum(req.total_quantity_needed or 0 for req in reqs)

                        reasoning_data = create_po_reasoning_low_stock(
                            supplier_name=supplier_name,
                            product_names=product_names,
                            current_stock=float(total_current),
                            required_stock=float(total_required),
                            days_until_stockout=days_until_delivery,
                            threshold_percentage=20,
                            affected_products=[req.product_name for req in reqs]
                        )
                    else:
                        # Use forecast-based reasoning
                        reasoning_data = create_po_reasoning_forecast_demand(
                            supplier_name=supplier_name,
                            product_names=product_names,
                            forecast_period_days=7,
                            total_demand=float(sum(req.order_demand or 0 for req in reqs))
                        )

                    # Generate PO number
                    po_number = await self._generate_po_number()

                    # Determine if needs approval (based on amount or config)
                    requires_approval = subtotal > 500 or not auto_approve  # Example threshold

                    # Create PO
                    po_data = {
                        'tenant_id': tenant_id,
                        'supplier_id': supplier_id,
                        'procurement_plan_id': plan_id,
                        'po_number': po_number,
                        'status': 'approved' if auto_approve and not requires_approval else 'pending_approval',
                        'priority': 'high' if days_until_delivery <= 2 else 'normal',
                        'order_date': datetime.now(timezone.utc),
                        'required_delivery_date': datetime.combine(required_delivery_date, datetime.min.time()),
                        'subtotal': Decimal(str(subtotal)),
                        'total_amount': Decimal(str(subtotal)),  # Simplified, no tax/shipping
                        'currency': 'EUR',
                        'requires_approval': requires_approval,
                        'reasoning_data': reasoning_data,  # NEW: Structured reasoning
                        'created_at': datetime.now(timezone.utc),
                        'updated_at': datetime.now(timezone.utc),
                        'created_by': uuid.uuid4(),  # System user
                        'updated_by': uuid.uuid4()
                    }

                    po = await self.po_repo.create_purchase_order(po_data)

                    # Create PO items
                    po_items = []
                    for req in reqs:
                        item_data = {
                            'tenant_id': tenant_id,
                            'purchase_order_id': po.id,
                            'procurement_requirement_id': req.id,
                            'inventory_product_id': req.product_id,
                            'product_name': req.product_name,
                            'ordered_quantity': req.net_requirement,
                            'unit_of_measure': req.unit_of_measure,
                            'unit_price': req.estimated_unit_cost or Decimal('0'),
                            'line_total': (req.estimated_unit_cost or Decimal('0')) * (req.net_requirement or Decimal('0')),
                            'remaining_quantity': req.net_requirement,
                            'created_at': datetime.now(timezone.utc),
                            'updated_at': datetime.now(timezone.utc)
                        }
                        item = await self.po_item_repo.create_po_item(item_data)
                        po_items.append(item)

                    created_pos.append({
                        'id': str(po.id),
                        'po_number': po.po_number,
                        'supplier_id': str(supplier_id),
                        'supplier_name': supplier_name,
                        'total_amount': float(po.total_amount),
                        'status': po.status.value if hasattr(po.status, 'value') else po.status,
                        'items_count': len(po_items)
                    })

                    logger.info(f"Created PO {po.po_number} for supplier {supplier_name} with {len(po_items)} items")

                except Exception as e:
                    logger.error(f"Error creating PO for supplier {supplier_id}: {e}", exc_info=True)
                    continue

            return {
                'success': True,
                'created_pos': created_pos,
                'count': len(created_pos)
            }

        except Exception as e:
            logger.error(f"Error in _create_purchase_orders_from_plan: {e}", exc_info=True)
            return {'success': False, 'created_pos': [], 'error': str(e)}

    async def _generate_po_number(self):
        """Generate unique PO number"""
        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        return f"PO-{timestamp}-{uuid.uuid4().hex[:6].upper()}"

    async def _get_supplier_by_id(self, tenant_id, supplier_id):
        """Get supplier details by ID"""
        try:
            return await self.suppliers_client.get_supplier_by_id(str(tenant_id), str(supplier_id))
        except Exception as e:
            logger.warning(f"Failed to get supplier {supplier_id}: {e}")
            return None

    async def _publish_plan_generated_event(self, tenant_id, plan_id):
        """Publish plan generated event"""
        try:
            await self.rabbitmq_client.publish_event(
                exchange='procurement',
                routing_key='plan.generated',
                message={
                    'tenant_id': str(tenant_id),
                    'plan_id': str(plan_id),
                    'timestamp': datetime.utcnow().isoformat()
                }
            )
        except Exception as e:
            logger.warning(f"Failed to publish event: {e}")
