"""
AI Insights Service HTTP Client
Shared client for all services to post and retrieve AI insights
"""

import httpx
from typing import Dict, List, Any, Optional
from uuid import UUID
import structlog
from datetime import datetime

logger = structlog.get_logger()


class AIInsightsClient:
    """
    HTTP client for AI Insights Service.
    Allows services to post insights, retrieve orchestration-ready insights, and record feedback.
    """

    def __init__(self, base_url: str, timeout: int = 30):
        """
        Initialize AI Insights client.

        Args:
            base_url: Base URL of AI Insights Service (e.g., http://ai-insights-service:8000)
            timeout: Request timeout in seconds
        """
        self.base_url = base_url.rstrip('/')
        self.timeout = timeout
        self.client = httpx.AsyncClient(timeout=self.timeout)

    async def close(self):
        """Close the HTTP client."""
        await self.client.aclose()

    async def create_insight(
        self,
        tenant_id: UUID,
        insight_data: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        Create a new insight in AI Insights Service.

        Args:
            tenant_id: Tenant UUID
            insight_data: Insight data dictionary with fields:
                - type: str (optimization, alert, prediction, recommendation, insight, anomaly)
                - priority: str (low, medium, high, critical)
                - category: str (forecasting, procurement, production, inventory, etc.)
                - title: str
                - description: str
                - impact_type: str
                - impact_value: float
                - impact_unit: str
                - confidence: int (0-100)
                - metrics_json: dict
                - actionable: bool
                - recommendation_actions: list (optional)
                - source_service: str
                - source_model: str (optional)

        Returns:
            Created insight dict or None if failed
        """
        url = f"{self.base_url}/api/v1/tenants/{tenant_id}/insights"

        try:
            # Ensure tenant_id is in the data
            insight_data['tenant_id'] = str(tenant_id)

            response = await self.client.post(url, json=insight_data)

            if response.status_code == 201:
                logger.info(
                    "Insight created successfully",
                    tenant_id=str(tenant_id),
                    insight_title=insight_data.get('title')
                )
                return response.json()
            else:
                logger.error(
                    "Failed to create insight",
                    status_code=response.status_code,
                    response=response.text,
                    insight_title=insight_data.get('title')
                )
                return None

        except Exception as e:
            logger.error(
                "Error creating insight",
                error=str(e),
                tenant_id=str(tenant_id)
            )
            return None

    async def create_insights_bulk(
        self,
        tenant_id: UUID,
        insights: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """
        Create multiple insights in bulk.

        Args:
            tenant_id: Tenant UUID
            insights: List of insight data dictionaries

        Returns:
            Dictionary with success/failure counts
        """
        results = {
            'total': len(insights),
            'successful': 0,
            'failed': 0,
            'created_insights': []
        }

        for insight_data in insights:
            result = await self.create_insight(tenant_id, insight_data)
            if result:
                results['successful'] += 1
                results['created_insights'].append(result)
            else:
                results['failed'] += 1

        logger.info(
            "Bulk insight creation complete",
            total=results['total'],
            successful=results['successful'],
            failed=results['failed']
        )

        return results

    async def get_insights(
        self,
        tenant_id: UUID,
        filters: Optional[Dict[str, Any]] = None
    ) -> Optional[Dict[str, Any]]:
        """
        Get insights for a tenant.

        Args:
            tenant_id: Tenant UUID
            filters: Optional filters:
                - category: str
                - priority: str
                - actionable_only: bool
                - min_confidence: int
                - page: int
                - page_size: int

        Returns:
            Paginated insights response or None if failed
        """
        url = f"{self.base_url}/api/v1/tenants/{tenant_id}/insights"

        try:
            response = await self.client.get(url, params=filters or {})

            if response.status_code == 200:
                return response.json()
            else:
                logger.error(
                    "Failed to get insights",
                    status_code=response.status_code
                )
                return None

        except Exception as e:
            logger.error("Error getting insights", error=str(e))
            return None

    async def get_orchestration_ready_insights(
        self,
        tenant_id: UUID,
        target_date: datetime,
        min_confidence: int = 70
    ) -> Optional[Dict[str, List[Dict[str, Any]]]]:
        """
        Get insights ready for orchestration workflow.

        Args:
            tenant_id: Tenant UUID
            target_date: Target date for orchestration
            min_confidence: Minimum confidence threshold

        Returns:
            Categorized insights or None if failed:
            {
                "forecast_adjustments": [...],
                "procurement_recommendations": [...],
                "production_adjustments": [...],
                "inventory_optimization": [...],
                "risk_alerts": [...]
            }
        """
        url = f"{self.base_url}/api/v1/tenants/{tenant_id}/insights/orchestration-ready"

        params = {
            'target_date': target_date.isoformat(),
            'min_confidence': min_confidence
        }

        try:
            response = await self.client.get(url, params=params)

            if response.status_code == 200:
                return response.json()
            else:
                logger.error(
                    "Failed to get orchestration insights",
                    status_code=response.status_code
                )
                return None

        except Exception as e:
            logger.error("Error getting orchestration insights", error=str(e))
            return None

    async def record_feedback(
        self,
        tenant_id: UUID,
        insight_id: UUID,
        feedback_data: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        Record feedback for an applied insight.

        Args:
            tenant_id: Tenant UUID
            insight_id: Insight UUID
            feedback_data: Feedback data with fields:
                - success: bool
                - applied_at: datetime (optional)
                - actual_impact_value: float (optional)
                - actual_impact_unit: str (optional)
                - notes: str (optional)

        Returns:
            Feedback response or None if failed
        """
        url = f"{self.base_url}/api/v1/tenants/{tenant_id}/insights/{insight_id}/feedback"

        try:
            feedback_data['insight_id'] = str(insight_id)

            response = await self.client.post(url, json=feedback_data)

            if response.status_code in [200, 201]:
                logger.info(
                    "Feedback recorded",
                    insight_id=str(insight_id),
                    success=feedback_data.get('success')
                )
                return response.json()
            else:
                logger.error(
                    "Failed to record feedback",
                    status_code=response.status_code
                )
                return None

        except Exception as e:
            logger.error("Error recording feedback", error=str(e))
            return None

    async def get_insights_summary(
        self,
        tenant_id: UUID,
        time_period_days: int = 30
    ) -> Optional[Dict[str, Any]]:
        """
        Get aggregate metrics summary for insights.

        Args:
            tenant_id: Tenant UUID
            time_period_days: Time period for metrics (default 30 days)

        Returns:
            Summary metrics or None if failed
        """
        url = f"{self.base_url}/api/v1/tenants/{tenant_id}/insights/metrics/summary"

        params = {'time_period_days': time_period_days}

        try:
            response = await self.client.get(url, params=params)

            if response.status_code == 200:
                return response.json()
            else:
                logger.error(
                    "Failed to get insights summary",
                    status_code=response.status_code
                )
                return None

        except Exception as e:
            logger.error("Error getting insights summary", error=str(e))
            return None

    async def post_accuracy_metrics(
        self,
        tenant_id: UUID,
        validation_date: datetime,
        metrics: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        Post forecast accuracy metrics to AI Insights Service.
        Creates an insight with accuracy validation results.

        Args:
            tenant_id: Tenant UUID
            validation_date: Date the forecasts were validated for
            metrics: Dictionary with accuracy metrics:
                - overall_mape: Mean Absolute Percentage Error
                - overall_rmse: Root Mean Squared Error
                - overall_mae: Mean Absolute Error
                - products_validated: Number of products validated
                - poor_accuracy_products: List of products with MAPE > 30%

        Returns:
            Created insight or None if failed
        """
        mape = metrics.get('overall_mape', 0)
        products_validated = metrics.get('products_validated', 0)
        poor_count = len(metrics.get('poor_accuracy_products', []))

        # Determine priority based on MAPE
        if mape > 40:
            priority = 'critical'
        elif mape > 30:
            priority = 'high'
        elif mape > 20:
            priority = 'medium'
        else:
            priority = 'low'

        # Create insight
        insight_data = {
            'type': 'insight',
            'priority': priority,
            'category': 'forecasting',
            'title': f'Forecast Accuracy Validation - {validation_date.strftime("%Y-%m-%d")}',
            'description': (
                f'Validated {products_validated} product forecasts against actual sales. '
                f'Overall MAPE: {mape:.2f}%. '
                f'{poor_count} products require retraining (MAPE > 30%).'
            ),
            'impact_type': 'accuracy',
            'impact_value': mape,
            'impact_unit': 'mape_percentage',
            'confidence': 100,  # Validation is based on actual data
            'metrics_json': {
                'validation_date': validation_date.isoformat() if hasattr(validation_date, 'isoformat') else str(validation_date),
                'overall_mape': mape,
                'overall_rmse': metrics.get('overall_rmse', 0),
                'overall_mae': metrics.get('overall_mae', 0),
                'products_validated': products_validated,
                'poor_accuracy_count': poor_count,
                'poor_accuracy_products': metrics.get('poor_accuracy_products', [])
            },
            'actionable': poor_count > 0,
            'recommendation_actions': [
                f'Retrain models for {poor_count} products with poor accuracy'
            ] if poor_count > 0 else [],
            'source_service': 'forecasting',
            'source_model': 'forecast_validation'
        }

        return await self.create_insight(tenant_id, insight_data)

    async def health_check(self) -> bool:
        """
        Check if AI Insights Service is healthy.

        Returns:
            True if healthy, False otherwise
        """
        url = f"{self.base_url}/health"

        try:
            response = await self.client.get(url)
            return response.status_code == 200

        except Exception as e:
            logger.error("AI Insights Service health check failed", error=str(e))
            return False
