from typing import Dict, List, Optional from datetime import datetime from common.log.module_logger import ModuleLogger from common.exception.exceptions import InvalidDataError from backend.business.tenant_notification_manager import TenantNotificationManager from backend.application.template_message_hub import TemplateMessageHub from backend.application.email_sender_hub import EmailSenderHub from backend.models.constants import NotificationConstants class TenantNotificationHub: def __init__(self): self.tenant_notification_manager = TenantNotificationManager() self.template_message_hub = TemplateMessageHub() self.email_sender_hub = EmailSenderHub() self.module_logger = ModuleLogger(sender_id="TenantNotificationHub") self.notification_constants = NotificationConstants() async def send_tenant_email( self, tenant_id: str, template_id: str, recipient_emails: List[str], region: int, subject_properties: Dict = {}, body_properties: Dict = {}, sender_email: str = None, priority: str = "normal", tracking_enabled: bool = True ): """Send email using tenant's template and email sender""" try: # 1. check if tenant has access to template await self.template_message_hub.verify_tenant_access(template_id, tenant_id, region) # 2. render template rendered_template = await self.template_message_hub.render_template( tenant_id=tenant_id, template_id=template_id, properties={**subject_properties, **body_properties}, region=region ) # 3. get tenant email sender default_sender_email = self.notification_constants.DEFAULT_EMAIL_SENDER if sender_email is None: tenant_email_sender = await self.email_sender_hub.get_email_sender(tenant_id) if not tenant_email_sender: sender_email = default_sender_email await self.module_logger.log_info( "Using default email sender for tenant", properties={ "tenant_id": tenant_id, "default_sender": default_sender_email } ) else: sender_email = tenant_email_sender # 4. call TenantNotificationManager to send email result = await self.tenant_notification_manager.send_tenant_email( tenant_id=tenant_id, template_id=template_id, rendered_template=rendered_template, recipient_emails=recipient_emails, sender_email=sender_email, region=region, priority=priority, tracking_enabled=tracking_enabled ) await self.module_logger.log_info( "Tenant email sent successfully", properties={ "tenant_id": tenant_id, "template_id": template_id, "recipient_count": len(recipient_emails), "sender_email": sender_email, "message_id": result.get("message_id") } ) return result except Exception as e: await self.module_logger.log_error( "Failed to send tenant email", properties={ "tenant_id": tenant_id, "template_id": template_id, "error": str(e) } ) raise async def get_tenant_email_status(self, tenant_id: str, email_id: str = None, recipient_email: str = None): """Get tenant email status""" try: status = await self.tenant_notification_manager.get_tenant_email_status(tenant_id, email_id, recipient_email) await self.module_logger.log_info( "Tenant email status retrieved", properties={ "tenant_id": tenant_id, "email_id": email_id, "status": status.get("status") if status else None } ) return status except Exception as e: await self.module_logger.log_error( "Failed to get tenant email status", properties={ "tenant_id": tenant_id, "email_id": email_id, "error": str(e) } ) raise async def get_tenant_email_status_list(self, tenant_id: str, limit: int = 50, offset: int = 0): """Get list of email statuses for a tenant""" try: status_list = await self.tenant_notification_manager.get_tenant_email_status_list(tenant_id, limit, offset) await self.module_logger.log_info( "Tenant email status list retrieved", properties={ "tenant_id": tenant_id, "count": len(status_list.get("emails", [])), "total_count": status_list.get("pagination", {}).get("total_count", 0) } ) return status_list except Exception as e: await self.module_logger.log_error( "Failed to get tenant email status list", properties={ "tenant_id": tenant_id, "error": str(e) } ) raise