# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Messaging service for sending messages across different channels.
Provides subscription-based messaging functionality.
"""

import logging
import re
from typing import List, Optional, Callable
from modules.datamodels.datamodelMessaging import (
    MessagingSubscription,
    MessagingSubscriptionRegistration,
    MessagingDelivery,
    MessagingChannel,
    MessagingEventParameters,
    MessagingSendResult,
    MessagingSubscriptionExecutionResult,
    DeliveryStatus
)
from modules.interfaces.interfaceMessaging import getInterface as getMessagingInterface
from modules.shared.timeUtils import getUtcTimestamp

logger = logging.getLogger(__name__)


class MessagingService:
    """
    Messaging service providing subscription-based messaging functionality.
    """
    
    def __init__(self, services):
        """Initialize messaging service with service center access.
        
        Args:
            services: Service center instance providing access to interfaces
        """
        self.services = services
        self._messagingInterface = None
    
    def sendMessage(
        self,
        subject: str,
        message: str,
        registration: MessagingSubscriptionRegistration
    ) -> MessagingSendResult:
        """
        Sendet eine Nachricht über einen Channel an einen User.
        Erstellt MessagingDelivery Record.
        
        Args:
            subject: Subject der Nachricht (für E-Mail, leer für SMS)
            message: Nachrichtentext
            registration: MessagingSubscriptionRegistration mit Channel-Info und userId
        
        Returns:
            MessagingSendResult mit Status und Delivery-ID
        """
        # Erstelle Delivery Record
        delivery = MessagingDelivery(
            subscriptionId=registration.subscriptionId,
            userId=registration.userId,
            channel=registration.channel,
            status=DeliveryStatus.PENDING
        )
        
        # Speichere Delivery Record
        try:
            deliveryRecord = self.services.interfaceDbComponent.createDelivery(delivery)
        except Exception as e:
            logger.error(f"Failed to create delivery record: {str(e)}")
            return MessagingSendResult(
                success=False,
                errorMessage=f"Failed to create delivery record: {str(e)}"
            )
        
        try:
            # Convert plain text to HTML for email channel
            messageToSend = message
            if registration.channel == MessagingChannel.EMAIL:
                messageToSend = self._textToHtml(message)
            
            # Versende über interfaceMessaging
            success = self._getMessagingInterface().send(
                channel=registration.channel,
                recipient=registration.channelConfig,
                subject=subject,
                message=messageToSend
            )
            
            if success:
                # Update Delivery Record
                self.services.interfaceDbComponent.updateDelivery(
                    deliveryRecord["id"],
                    {
                        "status": DeliveryStatus.SENT,
                        "sentAt": getUtcTimestamp()
                    }
                )
                return MessagingSendResult(
                    success=True,
                    deliveryId=deliveryRecord["id"]
                )
            else:
                # Update Delivery Record mit Fehler
                self.services.interfaceDbComponent.updateDelivery(
                    deliveryRecord["id"],
                    {
                        "status": DeliveryStatus.FAILED,
                        "errorMessage": "Failed to send message"
                    }
                )
                return MessagingSendResult(
                    success=False,
                    deliveryId=deliveryRecord["id"],
                    errorMessage="Failed to send message"
                )
        except Exception as e:
            logger.error(f"Error sending message: {str(e)}")
            # Update Delivery Record mit Fehler
            try:
                self.services.interfaceDbComponent.updateDelivery(
                    deliveryRecord["id"],
                    {
                        "status": DeliveryStatus.FAILED,
                        "errorMessage": str(e)
                    }
                )
            except Exception as updateError:
                logger.error(f"Failed to update delivery record: {str(updateError)}")
            
            return MessagingSendResult(
                success=False,
                deliveryId=deliveryRecord["id"],
                errorMessage=str(e)
            )
    
    def _textToHtml(self, text: str) -> str:
        """
        Convert plain text to simple HTML for email display.
        
        - Escapes HTML special characters
        - Converts newlines to <br> tags
        - Wraps URLs in clickable links
        - Wraps in a basic HTML structure with nice styling
        
        Args:
            text: Plain text message
        
        Returns:
            HTML formatted message
        """
        import html
        
        # Check if already HTML (contains HTML tags)
        if re.search(r'<[^>]+>', text):
            return text
        
        # Escape HTML special characters
        escaped = html.escape(text)
        
        # Convert URLs to clickable links (before converting newlines)
        urlPattern = r'(https?://[^\s<>"\']+)'
        escaped = re.sub(urlPattern, r'<a href="\1" style="color: #0066cc;">\1</a>', escaped)
        
        # Convert newlines to <br> tags
        escaped = escaped.replace('\n', '<br>\n')
        
        # Wrap in a nice HTML structure
        htmlContent = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            font-size: 14px;
            line-height: 1.6;
            color: #333333;
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
        }}
        a {{
            color: #0066cc;
        }}
    </style>
</head>
<body>
{escaped}
</body>
</html>"""
        
        return htmlContent
    
    def sendEmailDirect(
        self,
        recipient: str,
        subject: str,
        message: str,
        userId: Optional[str] = None
    ) -> bool:
        """
        Send email directly without requiring a subscription.
        Used for authentication flows (registration, password reset).
        
        Plain text messages are automatically converted to HTML format.
        
        Args:
            recipient: Email address of the recipient
            subject: Email subject
            message: Email body (can be HTML or plain text - plain text is auto-converted)
            userId: Optional user ID for logging/audit purposes
        
        Returns:
            bool: True if email was sent successfully, False otherwise
        """
        try:
            # Convert plain text to HTML if needed
            htmlMessage = self._textToHtml(message)
            
            messagingInterface = self._getMessagingInterface()
            success = messagingInterface.send(
                channel=MessagingChannel.EMAIL,
                recipient=recipient,
                subject=subject,
                message=htmlMessage
            )
            
            if success:
                logger.info(f"Email sent successfully to {recipient} (userId: {userId})")
            else:
                logger.warning(f"Failed to send email to {recipient} (userId: {userId})")
            
            return success
        except Exception as e:
            logger.error(f"Error sending email to {recipient}: {str(e)}", exc_info=True)
            return False
    
    def executeSubscription(
        self,
        subscriptionId: str,
        eventParameters: MessagingEventParameters
    ) -> MessagingSubscriptionExecutionResult:
        """
        Führt eine Subscription-Funktion aus.
        
        Args:
            subscriptionId: ID der Subscription
            eventParameters: Parameter vom Trigger (als Pydantic Model)
        
        Returns:
            MessagingSubscriptionExecutionResult
        
        Raises:
            ValueError: Wenn Subscription nicht existiert oder nicht enabled ist
            FileNotFoundError: Wenn Subscription-Funktion nicht gefunden wird
        """
        # Prüfe ob Subscription existiert und enabled ist
        subscription = self.services.interfaceDbComponent.getSubscription(subscriptionId)
        if not subscription:
            raise ValueError(f"Subscription {subscriptionId} not found")
        if not subscription.enabled:
            logger.warning(f"Subscription {subscriptionId} is disabled, skipping execution")
            return MessagingSubscriptionExecutionResult(
                success=False,
                messagesSent=0,
                errorMessage="Subscription is disabled"
            )
        
        # Hole alle aktiven Registrierungen für diese Subscription
        registrations = self._getSubscribers(subscriptionId)
        
        if not registrations:
            logger.info(f"No active registrations for subscription {subscriptionId}")
            return MessagingSubscriptionExecutionResult(
                success=True,
                messagesSent=0
            )
        
        # Lade Subscription-Funktion dynamisch
        subscriptionFunction = self._loadSubscriptionFunction(subscriptionId)
        if not subscriptionFunction:
            errorMsg = f"Subscription function not found for {subscriptionId}"
            logger.error(errorMsg)
            raise FileNotFoundError(errorMsg)
        
        # Führe Funktion aus mit Registrierungen
        try:
            return subscriptionFunction.execute(eventParameters, registrations, self)
        except Exception as e:
            logger.error(f"Error executing subscription {subscriptionId}: {str(e)}", exc_info=True)
            return MessagingSubscriptionExecutionResult(
                success=False,
                messagesSent=0,
                errorMessage=str(e)
            )
    
    def _getSubscribers(
        self,
        subscriptionId: str,
        channel: Optional[MessagingChannel] = None
    ) -> List[MessagingSubscriptionRegistration]:
        """Holt alle aktiven Subscriber einer Subscription"""
        filters = {"enabled": True}
        if channel:
            filters["channel"] = channel.value
        
        registrations = self.services.interfaceDbComponent.getAllRegistrations(
            subscriptionId=subscriptionId
        )
        
        # Filter nach enabled und channel
        filteredRegistrations = []
        for reg in registrations:
            if reg.enabled and (not channel or reg.channel == channel):
                filteredRegistrations.append(reg)
        
        return filteredRegistrations
    
    def _loadSubscriptionFunction(self, subscriptionId: str) -> Optional[Callable]:
        """
        Lädt die Subscription-Funktion dynamisch.
        
        Returns:
            Callable mit execute-Methode oder None wenn nicht gefunden
        
        Note:
            subscriptionId wird direkt als Dateiname verwendet (z.B. "SystemErrors" -> subSubscriptionSystemErrors.py)
        """
        # Format: subSubscription{subscriptionId}.py
        functionName = f"subSubscription{subscriptionId}"
        moduleName = f"modules.services.serviceMessaging.subscriptions.{functionName}"
        
        try:
            # Dynamisches Import
            import importlib
            subscriptionModule = importlib.import_module(moduleName)
            return subscriptionModule
        except ImportError:
            # Funktion existiert noch nicht - das ist OK
            logger.debug(f"Subscription function {moduleName} not found (this is OK if not yet implemented)")
            return None
    
    def _getMessagingInterface(self):
        """Holt das Messaging-Interface (interfaceMessaging)"""
        if not self._messagingInterface:
            self._messagingInterface = getMessagingInterface()
        return self._messagingInterface

