"""
Demand Insights Orchestrator
Coordinates demand forecasting analysis and insight posting
"""

import pandas as pd
from typing import Dict, List, Any, Optional
import structlog
from datetime import datetime
from uuid import UUID
import sys
import os

# Add shared clients to path
sys.path.append(os.path.join(os.path.dirname(__file__), '../../../..'))
from shared.clients.ai_insights_client import AIInsightsClient
from shared.messaging import UnifiedEventPublisher

from app.ml.predictor import BakeryForecaster

logger = structlog.get_logger()


class DemandInsightsOrchestrator:
    """
    Orchestrates demand forecasting analysis and insight generation workflow.

    Workflow:
    1. Analyze historical demand patterns from sales data
    2. Generate insights for demand optimization
    3. Post insights to AI Insights Service
    4. Publish recommendation events to RabbitMQ
    5. Provide demand pattern analysis for forecasting
    6. Track demand forecasting performance
    """

    def __init__(
        self,
        ai_insights_base_url: str = "http://ai-insights-service:8000",
        event_publisher: Optional[UnifiedEventPublisher] = None
    ):
        self.forecaster = BakeryForecaster()
        self.ai_insights_client = AIInsightsClient(ai_insights_base_url)
        self.event_publisher = event_publisher

    async def analyze_and_post_demand_insights(
        self,
        tenant_id: str,
        inventory_product_id: str,
        sales_data: pd.DataFrame,
        forecast_horizon_days: int = 30,
        min_history_days: int = 90
    ) -> Dict[str, Any]:
        """
        Complete workflow: Analyze demand and post insights.

        Args:
            tenant_id: Tenant identifier
            inventory_product_id: Product identifier
            sales_data: Historical sales data
            forecast_horizon_days: Days to forecast ahead
            min_history_days: Minimum days of history required

        Returns:
            Workflow results with analysis and posted insights
        """
        logger.info(
            "Starting demand forecasting analysis workflow",
            tenant_id=tenant_id,
            inventory_product_id=inventory_product_id,
            history_days=len(sales_data)
        )

        # Step 1: Analyze demand patterns
        analysis_results = await self.forecaster.analyze_demand_patterns(
            tenant_id=tenant_id,
            inventory_product_id=inventory_product_id,
            sales_data=sales_data,
            forecast_horizon_days=forecast_horizon_days,
            min_history_days=min_history_days
        )

        logger.info(
            "Demand analysis complete",
            inventory_product_id=inventory_product_id,
            insights_generated=len(analysis_results.get('insights', []))
        )

        # Step 2: Enrich insights with tenant_id and product context
        enriched_insights = self._enrich_insights(
            analysis_results.get('insights', []),
            tenant_id,
            inventory_product_id
        )

        # Step 3: Post insights to AI Insights Service
        if enriched_insights:
            post_results = await self.ai_insights_client.create_insights_bulk(
                tenant_id=UUID(tenant_id),
                insights=enriched_insights
            )

            logger.info(
                "Demand insights posted to AI Insights Service",
                inventory_product_id=inventory_product_id,
                total=post_results['total'],
                successful=post_results['successful'],
                failed=post_results['failed']
            )
        else:
            post_results = {'total': 0, 'successful': 0, 'failed': 0}
            logger.info("No insights to post for product", inventory_product_id=inventory_product_id)

        # Step 4: Publish insight events to RabbitMQ
        created_insights = post_results.get('created_insights', [])
        if created_insights:
            product_context = {'inventory_product_id': inventory_product_id}
            await self._publish_insight_events(
                tenant_id=tenant_id,
                insights=created_insights,
                product_context=product_context
            )

        # Step 5: Return comprehensive results
        return {
            'tenant_id': tenant_id,
            'inventory_product_id': inventory_product_id,
            'analyzed_at': analysis_results['analyzed_at'],
            'history_days': analysis_results['history_days'],
            'demand_patterns': analysis_results.get('patterns', {}),
            'trend_analysis': analysis_results.get('trend_analysis', {}),
            'seasonal_factors': analysis_results.get('seasonal_factors', {}),
            'insights_generated': len(enriched_insights),
            'insights_posted': post_results['successful'],
            'insights_failed': post_results['failed'],
            'created_insights': post_results.get('created_insights', [])
        }

    def _enrich_insights(
        self,
        insights: List[Dict[str, Any]],
        tenant_id: str,
        inventory_product_id: str
    ) -> List[Dict[str, Any]]:
        """
        Enrich insights with required fields for AI Insights Service.

        Args:
            insights: Raw insights from forecaster
            tenant_id: Tenant identifier
            inventory_product_id: Product identifier

        Returns:
            Enriched insights ready for posting
        """
        enriched = []

        for insight in insights:
            # Add required tenant_id
            enriched_insight = insight.copy()
            enriched_insight['tenant_id'] = tenant_id

            # Add product context to metrics
            if 'metrics_json' not in enriched_insight:
                enriched_insight['metrics_json'] = {}

            enriched_insight['metrics_json']['inventory_product_id'] = inventory_product_id

            # Add source metadata
            enriched_insight['source_service'] = 'forecasting'
            enriched_insight['source_model'] = 'demand_analyzer'
            enriched_insight['detected_at'] = datetime.utcnow().isoformat()

            enriched.append(enriched_insight)

        return enriched

    async def analyze_all_products(
        self,
        tenant_id: str,
        products_data: Dict[str, pd.DataFrame],
        forecast_horizon_days: int = 30,
        min_history_days: int = 90
    ) -> Dict[str, Any]:
        """
        Analyze all products for a tenant and generate comparative insights.

        Args:
            tenant_id: Tenant identifier
            products_data: Dict of {inventory_product_id: sales_data DataFrame}
            forecast_horizon_days: Days to forecast
            min_history_days: Minimum history required

        Returns:
            Comprehensive analysis with product comparison
        """
        logger.info(
            "Analyzing all products for tenant",
            tenant_id=tenant_id,
            products=len(products_data)
        )

        all_results = []
        total_insights_posted = 0

        # Analyze each product
        for inventory_product_id, sales_data in products_data.items():
            try:
                results = await self.analyze_and_post_demand_insights(
                    tenant_id=tenant_id,
                    inventory_product_id=inventory_product_id,
                    sales_data=sales_data,
                    forecast_horizon_days=forecast_horizon_days,
                    min_history_days=min_history_days
                )

                all_results.append(results)
                total_insights_posted += results['insights_posted']

            except Exception as e:
                logger.error(
                    "Error analyzing product",
                    inventory_product_id=inventory_product_id,
                    error=str(e)
                )

        # Generate summary insight
        if total_insights_posted > 0:
            summary_insight = self._generate_portfolio_summary_insight(
                tenant_id, all_results
            )

            if summary_insight:
                enriched_summary = self._enrich_insights(
                    [summary_insight], tenant_id, 'all_products'
                )

                post_results = await self.ai_insights_client.create_insights_bulk(
                    tenant_id=UUID(tenant_id),
                    insights=enriched_summary
                )

                total_insights_posted += post_results['successful']

        logger.info(
            "All products analysis complete",
            tenant_id=tenant_id,
            products_analyzed=len(all_results),
            total_insights_posted=total_insights_posted
        )

        return {
            'tenant_id': tenant_id,
            'analyzed_at': datetime.utcnow().isoformat(),
            'products_analyzed': len(all_results),
            'product_results': all_results,
            'total_insights_posted': total_insights_posted
        }

    def _generate_portfolio_summary_insight(
        self,
        tenant_id: str,
        all_results: List[Dict[str, Any]]
    ) -> Optional[Dict[str, Any]]:
        """
        Generate portfolio-level summary insight.

        Args:
            tenant_id: Tenant identifier
            all_results: All product analysis results

        Returns:
            Summary insight or None
        """
        if not all_results:
            return None

        # Calculate summary statistics
        total_products = len(all_results)
        high_demand_products = sum(1 for r in all_results if r.get('trend_analysis', {}).get('is_increasing', False))
        
        avg_seasonal_factor = sum(
            r.get('seasonal_factors', {}).get('peak_ratio', 1.0) 
            for r in all_results 
            if r.get('seasonal_factors', {}).get('peak_ratio')
        ) / max(1, len(all_results))

        return {
            'type': 'recommendation',
            'priority': 'medium' if high_demand_products > total_products * 0.5 else 'low',
            'category': 'forecasting',
            'title': f'Demand Pattern Summary: {total_products} Products Analyzed',
            'description': f'Detected {high_demand_products} products with increasing demand trends. Average seasonal peak ratio: {avg_seasonal_factor:.2f}x.',
            'impact_type': 'demand_optimization',
            'impact_value': high_demand_products,
            'impact_unit': 'products',
            'confidence': 75,
            'metrics_json': {
                'total_products': total_products,
                'high_demand_products': high_demand_products,
                'avg_seasonal_factor': round(avg_seasonal_factor, 2),
                'trend_strength': 'strong' if high_demand_products > total_products * 0.7 else 'moderate'
            },
            'actionable': True,
            'recommendation_actions': [
                {
                    'label': 'Review Production Schedule',
                    'action': 'review_production_schedule',
                    'params': {'tenant_id': tenant_id}
                },
                {
                    'label': 'Adjust Inventory Levels',
                    'action': 'adjust_inventory_levels',
                    'params': {'tenant_id': tenant_id}
                }
            ],
            'source_service': 'forecasting',
            'source_model': 'demand_analyzer'
        }

    async def get_demand_patterns(
        self,
        inventory_product_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get cached demand patterns for a product.

        Args:
            inventory_product_id: Product identifier

        Returns:
            Demand patterns or None if not analyzed
        """
        return self.forecaster.get_cached_demand_patterns(inventory_product_id)

    async def _publish_insight_events(self, tenant_id, insights, product_context=None):
        """
        Publish insight events to RabbitMQ for alert processing.

        Args:
            tenant_id: Tenant identifier
            insights: List of created insights
            product_context: Additional context about the product
        """
        if not self.event_publisher:
            logger.warning("No event publisher available for demand insights")
            return

        for insight in insights:
            # Determine severity based on confidence and priority
            confidence = insight.get('confidence', 0)
            priority = insight.get('priority', 'medium')
            
            # Map priority to severity, with confidence as tiebreaker
            if priority == 'critical' or (priority == 'high' and confidence >= 70):
                severity = 'high'
            elif priority == 'high' or (priority == 'medium' and confidence >= 80):
                severity = 'medium'
            else:
                severity = 'low'

            # Prepare the event data
            event_data = {
                'insight_id': insight.get('id'),
                'type': insight.get('type'),
                'title': insight.get('title'),
                'description': insight.get('description'),
                'category': insight.get('category'),
                'priority': insight.get('priority'),
                'confidence': confidence,
                'recommendation': insight.get('recommendation_actions', []),
                'impact_type': insight.get('impact_type'),
                'impact_value': insight.get('impact_value'),
                'inventory_product_id': product_context.get('inventory_product_id') if product_context else None,
                'timestamp': insight.get('detected_at', datetime.utcnow().isoformat()),
                'source_service': 'forecasting',
                'source_model': 'demand_analyzer'
            }

            try:
                await self.event_publisher.publish_recommendation(
                    event_type='ai_demand_forecast',
                    tenant_id=tenant_id,
                    severity=severity,
                    data=event_data
                )
                logger.info(
                    "Published demand insight event",
                    tenant_id=tenant_id,
                    insight_id=insight.get('id'),
                    severity=severity
                )
            except Exception as e:
                logger.error(
                    "Failed to publish demand insight event",
                    tenant_id=tenant_id,
                    insight_id=insight.get('id'),
                    error=str(e)
                )

    async def close(self):
        """Close HTTP client connections."""
        await self.ai_insights_client.close()