"""
Notification manager for coordinating multiple notification services.

This module provides a unified interface for managing and sending notifications
across multiple services (Telegram, Discord, etc.).
"""

from threading import RLock
from typing import Dict, List, Optional, Callable
from datetime import datetime

from .types import (
    NotificationService,
    NotificationConfig,
    NotificationMessage,
    NotificationResult,
    NotificationStats,
    NotificationPriority,
    NotificationType,
    NotificationCallback,
    ErrorCallback,
)
from .telegram import TelegramNotifier
from .discord import DiscordNotifier


class NotificationManager:
    """
    Central manager for notification services.
    
    Manages multiple notification services and provides:
    - Unified sending interface
    - Priority filtering
    - Type filtering
    - Statistics tracking
    - Error handling
    - Callbacks
    
    Thread-safe implementation.
    """
    
    def __init__(self):
        """Initialize notification manager."""
        self._lock = RLock()
        self._services: Dict[NotificationService, any] = {}
        self._configs: Dict[NotificationService, NotificationConfig] = {}
        self._global_callback: Optional[NotificationCallback] = None
        self._error_callback: Optional[ErrorCallback] = None
    
    def add_service(self, config: NotificationConfig) -> None:
        """
        Add a notification service.
        
        Args:
            config: Notification configuration
            
        Raises:
            ValueError: If service is already configured
        """
        with self._lock:
            if config.service in self._services:
                raise ValueError(f"Service {config.service} is already configured")
            
            # Create appropriate notifier
            if config.service == NotificationService.TELEGRAM:
                if not config.telegram_config:
                    raise ValueError("Telegram config is required")
                notifier = TelegramNotifier(config.telegram_config)
            elif config.service == NotificationService.DISCORD:
                if not config.discord_config:
                    raise ValueError("Discord config is required")
                notifier = DiscordNotifier(config.discord_config)
            else:
                raise ValueError(f"Unsupported service: {config.service}")
            
            self._services[config.service] = notifier
            self._configs[config.service] = config
    
    def remove_service(self, service: NotificationService) -> None:
        """
        Remove a notification service.
        
        Args:
            service: Service to remove
        """
        with self._lock:
            self._services.pop(service, None)
            self._configs.pop(service, None)
    
    def has_service(self, service: NotificationService) -> bool:
        """
        Check if a service is configured.
        
        Args:
            service: Service to check
            
        Returns:
            True if service is configured, False otherwise
        """
        with self._lock:
            return service in self._services
    
    def send(
        self,
        message: NotificationMessage,
        services: Optional[List[NotificationService]] = None,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send notification to one or more services.
        
        Args:
            message: Message to send
            services: List of services to send to (None = all services)
            
        Returns:
            Dictionary mapping services to their results
        """
        with self._lock:
            results = {}
            
            # Determine which services to use
            target_services = services or list(self._services.keys())
            
            for service in target_services:
                if service not in self._services:
                    continue
                
                config = self._configs[service]
                notifier = self._services[service]
                
                # Check if service is enabled
                if not config.enabled:
                    continue
                
                # Check priority filter
                if message.priority.value < config.min_priority.value:
                    continue
                
                # Check type filter
                if (config.enabled_types and 
                    message.notification_type not in config.enabled_types):
                    continue
                
                try:
                    # Send notification
                    result = notifier.send(
                        message,
                        max_retries=config.max_retries,
                        retry_delay=config.retry_delay,
                    )
                    
                    results[service] = result
                    
                    # Call global callback
                    if self._global_callback:
                        try:
                            self._global_callback(result)
                        except Exception:
                            pass  # Ignore callback errors
                    
                except Exception as e:
                    # Handle error
                    result = NotificationResult(
                        success=False,
                        error=str(e),
                    )
                    results[service] = result
                    
                    # Call error callback
                    if self._error_callback:
                        try:
                            self._error_callback(e, message)
                        except Exception:
                            pass  # Ignore callback errors
            
            return results
    
    def send_alert(
        self,
        title: str,
        body: str,
        priority: NotificationPriority = NotificationPriority.HIGH,
        **kwargs,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send an alert notification.
        
        Args:
            title: Alert title
            body: Alert body
            priority: Alert priority
            **kwargs: Additional message parameters
            
        Returns:
            Dictionary mapping services to their results
        """
        message = NotificationMessage(
            title=title,
            body=body,
            notification_type=NotificationType.ALERT,
            priority=priority,
            **kwargs,
        )
        return self.send(message)
    
    def send_pnl_update(
        self,
        title: str,
        body: str,
        priority: NotificationPriority = NotificationPriority.NORMAL,
        **kwargs,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send a PnL update notification.
        
        Args:
            title: Update title
            body: Update body
            priority: Update priority
            **kwargs: Additional message parameters
            
        Returns:
            Dictionary mapping services to their results
        """
        message = NotificationMessage(
            title=title,
            body=body,
            notification_type=NotificationType.PNL_UPDATE,
            priority=priority,
            **kwargs,
        )
        return self.send(message)
    
    def send_position_change(
        self,
        title: str,
        body: str,
        priority: NotificationPriority = NotificationPriority.NORMAL,
        **kwargs,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send a position change notification.
        
        Args:
            title: Change title
            body: Change body
            priority: Change priority
            **kwargs: Additional message parameters
            
        Returns:
            Dictionary mapping services to their results
        """
        message = NotificationMessage(
            title=title,
            body=body,
            notification_type=NotificationType.POSITION_CHANGE,
            priority=priority,
            **kwargs,
        )
        return self.send(message)
    
    def send_strategy_recommendation(
        self,
        title: str,
        body: str,
        priority: NotificationPriority = NotificationPriority.NORMAL,
        **kwargs,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send a strategy recommendation notification.
        
        Args:
            title: Recommendation title
            body: Recommendation body
            priority: Recommendation priority
            **kwargs: Additional message parameters
            
        Returns:
            Dictionary mapping services to their results
        """
        message = NotificationMessage(
            title=title,
            body=body,
            notification_type=NotificationType.STRATEGY_RECOMMENDATION,
            priority=priority,
            **kwargs,
        )
        return self.send(message)
    
    def send_report_ready(
        self,
        title: str,
        body: str,
        priority: NotificationPriority = NotificationPriority.LOW,
        **kwargs,
    ) -> Dict[NotificationService, NotificationResult]:
        """
        Send a report ready notification.
        
        Args:
            title: Report title
            body: Report body
            priority: Report priority
            **kwargs: Additional message parameters
            
        Returns:
            Dictionary mapping services to their results
        """
        message = NotificationMessage(
            title=title,
            body=body,
            notification_type=NotificationType.REPORT_READY,
            priority=priority,
            **kwargs,
        )
        return self.send(message)
    
    def set_callback(self, callback: NotificationCallback) -> None:
        """
        Set global notification callback.
        
        Args:
            callback: Callback function to call after each notification
        """
        with self._lock:
            self._global_callback = callback
    
    def set_error_callback(self, callback: ErrorCallback) -> None:
        """
        Set error callback.
        
        Args:
            callback: Callback function to call on errors
        """
        with self._lock:
            self._error_callback = callback
    
    def get_stats(
        self,
        service: Optional[NotificationService] = None,
    ) -> Dict[NotificationService, NotificationStats]:
        """
        Get notification statistics.
        
        Args:
            service: Specific service to get stats for (None = all services)
            
        Returns:
            Dictionary mapping services to their statistics
        """
        with self._lock:
            if service:
                if service not in self._services:
                    return {}
                return {service: self._services[service].get_stats()}
            
            return {
                svc: notifier.get_stats()
                for svc, notifier in self._services.items()
            }
    
    def reset_stats(self, service: Optional[NotificationService] = None) -> None:
        """
        Reset notification statistics.
        
        Args:
            service: Specific service to reset (None = all services)
        """
        with self._lock:
            if service:
                if service in self._services:
                    self._services[service].reset_stats()
            else:
                for notifier in self._services.values():
                    notifier.reset_stats()
    
    def test_connection(
        self,
        service: Optional[NotificationService] = None,
    ) -> Dict[NotificationService, bool]:
        """
        Test connection to notification services.
        
        Args:
            service: Specific service to test (None = all services)
            
        Returns:
            Dictionary mapping services to connection status
        """
        with self._lock:
            results = {}
            
            if service:
                if service in self._services:
                    results[service] = self._services[service].test_connection()
            else:
                for svc, notifier in self._services.items():
                    results[svc] = notifier.test_connection()
            
            return results
    
    def get_configured_services(self) -> List[NotificationService]:
        """
        Get list of configured services.
        
        Returns:
            List of configured services
        """
        with self._lock:
            return list(self._services.keys())
