# services/notification/app/services/notification_orchestrator.py
"""
Notification orchestrator for managing delivery across all channels
Includes SSE integration for real-time dashboard updates
"""

from typing import List, Dict, Any
from datetime import datetime
import structlog

from .email_service import EmailService
from .whatsapp_service import WhatsAppService
from .sse_service import SSEService

logger = structlog.get_logger()

class NotificationOrchestrator:
    """
    Orchestrates delivery across all notification channels
    Now includes SSE for real-time dashboard updates, with support for recommendations
    """
    
    def __init__(
        self,
        email_service: EmailService,
        whatsapp_service: WhatsAppService,
        sse_service: SSEService,
        push_service=None  # Optional push service
    ):
        self.email_service = email_service
        self.whatsapp_service = whatsapp_service
        self.sse_service = sse_service
        self.push_service = push_service
        
    async def send_notification(
        self,
        tenant_id: str,
        notification: Dict[str, Any],
        channels: List[str]
    ) -> Dict[str, Any]:
        """
        Send notification through specified channels
        Channels can include: email, whatsapp, push, dashboard (SSE)
        """
        results = {}
        
        # Always send to dashboard for visibility (SSE)
        if 'dashboard' in channels or notification.get('type') in ['alert', 'recommendation']:
            try:
                await self.sse_service.send_item_notification(
                    tenant_id,
                    notification
                )
                results['dashboard'] = {'status': 'sent', 'timestamp': datetime.utcnow().isoformat()}
                logger.info("Item sent to dashboard via SSE", 
                          tenant_id=tenant_id, 
                          item_type=notification.get('type'),
                          item_id=notification.get('id'))
            except Exception as e:
                logger.error("Failed to send to dashboard", 
                           tenant_id=tenant_id, 
                           error=str(e))
                results['dashboard'] = {'status': 'failed', 'error': str(e)}
        
        # Send to email channel
        if 'email' in channels:
            try:
                email_result = await self.email_service.send_notification_email(
                    to_email=notification.get('email'),
                    subject=notification.get('title'),
                    template_data={
                        'title': notification.get('title'),
                        'message': notification.get('message'),
                        'severity': notification.get('severity'),
                        'item_type': notification.get('type'),
                        'actions': notification.get('actions', []),
                        'metadata': notification.get('metadata', {}),
                        'timestamp': datetime.utcnow().isoformat()
                    },
                    notification_type=notification.get('type', 'alert')
                )
                results['email'] = email_result
            except Exception as e:
                logger.error("Failed to send email", 
                           tenant_id=tenant_id, 
                           error=str(e))
                results['email'] = {'status': 'failed', 'error': str(e)}
                
        # Send to WhatsApp channel
        if 'whatsapp' in channels:
            try:
                whatsapp_result = await self.whatsapp_service.send_notification_message(
                    to_phone=notification.get('phone'),
                    message=self._format_whatsapp_message(notification),
                    notification_type=notification.get('type', 'alert')
                )
                results['whatsapp'] = whatsapp_result
            except Exception as e:
                logger.error("Failed to send WhatsApp", 
                           tenant_id=tenant_id, 
                           error=str(e))
                results['whatsapp'] = {'status': 'failed', 'error': str(e)}
                
        # Send to push notification channel
        if 'push' in channels and self.push_service:
            try:
                push_result = await self.push_service.send_notification(
                    user_id=notification.get('user_id'),
                    title=notification.get('title'),
                    body=notification.get('message'),
                    data={
                        'item_type': notification.get('type'),
                        'severity': notification.get('severity'),
                        'item_id': notification.get('id'),
                        'metadata': notification.get('metadata', {})
                    }
                )
                results['push'] = push_result
            except Exception as e:
                logger.error("Failed to send push notification", 
                           tenant_id=tenant_id, 
                           error=str(e))
                results['push'] = {'status': 'failed', 'error': str(e)}
        
        # Log summary
        successful_channels = [ch for ch, result in results.items() if result.get('status') == 'sent']
        failed_channels = [ch for ch, result in results.items() if result.get('status') == 'failed']
        
        logger.info("Notification delivery completed", 
                  tenant_id=tenant_id,
                  item_type=notification.get('type'),
                  item_id=notification.get('id'),
                  successful_channels=successful_channels,
                  failed_channels=failed_channels,
                  total_channels=len(channels))
        
        return {
            'status': 'completed',
            'successful_channels': successful_channels,
            'failed_channels': failed_channels,
            'results': results,
            'timestamp': datetime.utcnow().isoformat()
        }
    
    def _format_whatsapp_message(self, notification: Dict[str, Any]) -> str:
        """Format message for WhatsApp with emojis and structure"""
        item_type = notification.get('type', 'alert')
        severity = notification.get('severity', 'medium')
        
        # Get appropriate emoji
        type_emoji = '🚨' if item_type == 'alert' else '💡'
        severity_emoji = {
            'urgent': '🔴',
            'high': '🟡', 
            'medium': '🔵',
            'low': '🟢'
        }.get(severity, '🔵')
        
        message = f"{type_emoji} {severity_emoji} *{notification.get('title', 'Notificación')}*\n\n"
        message += f"{notification.get('message', '')}\n"
        
        # Add actions if available
        actions = notification.get('actions', [])
        if actions and len(actions) > 0:
            message += "\n*Acciones sugeridas:*\n"
            for i, action in enumerate(actions[:3], 1):  # Limit to 3 actions for WhatsApp
                message += f"{i}. {action}\n"
        
        # Add timestamp
        message += f"\n_Enviado: {datetime.now().strftime('%H:%M, %d/%m/%Y')}_"
        
        return message
    
    def get_channels_by_severity(self, severity: str, item_type: str, hour: int = None) -> List[str]:
        """
        Determine notification channels based on severity and item_type
        Now includes 'dashboard' as a channel
        """
        if hour is None:
            hour = datetime.now().hour
            
        # Dashboard always gets all items
        channels = ['dashboard']
        
        if item_type == 'alert':
            if severity == 'urgent':
                # Urgent alerts: All channels immediately
                channels.extend(['email', 'whatsapp', 'push'])
                
            elif severity == 'high':
                # High alerts: Email and WhatsApp during extended hours
                if 6 <= hour <= 22:
                    channels.extend(['email', 'whatsapp'])
                else:
                    channels.append('email')  # Email only during night
                
            elif severity == 'medium':
                # Medium alerts: Email during business hours
                if 7 <= hour <= 20:
                    channels.append('email')
                    
        elif item_type == 'recommendation':
            # Recommendations: Generally less urgent, respect business hours
            if severity in ['medium', 'high']:
                if 8 <= hour <= 19:  # Stricter business hours for recommendations
                    channels.append('email')
            # Low/urgent: Dashboard only (urgent rare for recommendations)
        
        return channels
    
    async def health_check(self) -> Dict[str, Any]:
        """Check health of all notification channels"""
        health_status = {
            'status': 'healthy',
            'channels': {},
            'timestamp': datetime.utcnow().isoformat()
        }
        
        # Check email service
        try:
            email_health = await self.email_service.health_check()
            health_status['channels']['email'] = email_health
        except Exception as e:
            health_status['channels']['email'] = {'status': 'unhealthy', 'error': str(e)}
        
        # Check WhatsApp service
        try:
            whatsapp_health = await self.whatsapp_service.health_check()
            health_status['channels']['whatsapp'] = whatsapp_health
        except Exception as e:
            health_status['channels']['whatsapp'] = {'status': 'unhealthy', 'error': str(e)}
        
        # Check SSE service
        try:
            sse_metrics = self.sse_service.get_metrics()
            sse_status = 'healthy' if sse_metrics['redis_connected'] else 'unhealthy'
            health_status['channels']['sse'] = {
                'status': sse_status,
                'metrics': sse_metrics
            }
        except Exception as e:
            health_status['channels']['sse'] = {'status': 'unhealthy', 'error': str(e)}
        
        # Check push service if available
        if self.push_service:
            try:
                push_health = await self.push_service.health_check()
                health_status['channels']['push'] = push_health
            except Exception as e:
                health_status['channels']['push'] = {'status': 'unhealthy', 'error': str(e)}
        
        # Determine overall status
        unhealthy_channels = [
            ch for ch, status in health_status['channels'].items() 
            if status.get('status') != 'healthy'
        ]
        
        if unhealthy_channels:
            health_status['status'] = 'degraded' if len(unhealthy_channels) < len(health_status['channels']) else 'unhealthy'
            health_status['unhealthy_channels'] = unhealthy_channels
        
        return health_status
    
    def get_metrics(self) -> Dict[str, Any]:
        """Get aggregated metrics from all services"""
        metrics = {
            'timestamp': datetime.utcnow().isoformat(),
            'channels': {}
        }
        
        # Get SSE metrics
        try:
            metrics['channels']['sse'] = self.sse_service.get_metrics()
        except Exception as e:
            logger.error("Failed to get SSE metrics", error=str(e))
        
        # Additional metrics could be added here for other services
        
        return metrics