U
    hW                     @   s   d Z ddlZddlZddlZddlZddlmZmZmZm	Z	 ddl
m
Z
mZ ddlmZ ddlmZ ddlmZ ddlmZ d	d
lmZmZmZmZ G dd dZG dd dZG dd dZG dd dZdS )a  
Notification Services

This module contains services for sending notifications through various
channels including Telegram, email, webhooks, and other messaging platforms.
It provides a unified interface for notification delivery with retry logic
and error handling.
    N)OptionalDictAnyList)datetime	timedelta)settings)timezone)	send_mail)render_to_string   )NotificationChannelNotificationTemplateNotificationNotificationRulec                   @   s   e Zd ZdZdee ee dddZddddZdeee eee	ee
f dddZdeeee e	ee
f dddZeeeeeedddZdeeee ee eedddZdS )TelegramServicea  
    Service for sending notifications via Telegram Bot API.
    
    This service handles Telegram bot integration, message formatting,
    and delivery with automatic retry logic for failed messages.
    
    Attributes:
        logger (Logger): Logger instance for recording operations
        bot_token (str): Telegram bot token from configuration
        default_chat_id (str): Default chat ID for notifications
        api_base_url (str): Base URL for Telegram Bot API
    N)	bot_tokenchat_idc                 C   sN   t d| _|ptjdd| _|p0tjdd| _d| j | _| 	  dS )z
        Initialize the Telegram service.
        
        Args:
            bot_token (str, optional): Telegram bot token, uses settings if not provided
            chat_id (str, optional): Default chat ID, uses settings if not provided
        zstream_processor.telegram	BOT_TOKEN CHAT_IDzhttps://api.telegram.org/botN)
logging	getLoggerloggerr   TELEGRAM_CONFIGgetr   default_chat_idapi_base_url_validate_config)selfr   r    r    @/var/www/html/StreamProcessor/src/apps/notifications/services.py__init__)   s
    	zTelegramService.__init__)returnc                 C   s<   | j s| jd dS t| j dk r,td| jd dS )z
        Validate Telegram configuration.
        
        Raises:
            ValueError: If required configuration is missing
        z:Telegram bot token not configured - notifications disabledN   z!Invalid Telegram bot token formatz)Telegram service initialized successfully)r   r   warninglen
ValueErrorinfor   r    r    r!   r   >   s    z TelegramService._validate_configHTMLT)messager   
parse_modedisable_web_page_previewr#   c              
   C   s  | j s| jd dddS |p$| j}|s@| jd dddS | j d}||||d}z| jd	|  tj||d
ddid}|j	dkr|
 }	|	dr| jd|	d d   |	W S |	dd}
| jd|
  td|
 n6| jd|j	 d|j  td|j	 d|j W n^ tjk
rN   | jd  Y n: tjk
r } z| jd|   W 5 d}~X Y nX dS )a  
        Send a text message via Telegram.
        
        Args:
            message (str): Message text to send
            chat_id (str, optional): Target chat ID, uses default if not provided
            parse_mode (str): Message parse mode (HTML, Markdown, or None)
            disable_web_page_preview (bool): Disable link previews
            
        Returns:
            Dict[str, Any]: API response data
            
        Raises:
            requests.RequestException: If API request fails
        z8Telegram bot token not configured, skipping notificationskippedZbot_token_not_configured)statusreason-No chat ID provided and no default configuredZ
no_chat_idz/sendMessage)r   textr,   r-   z!Sending Telegram message to chat    Content-Typeapplication/json)jsontimeoutheaders   okz$Telegram message sent successfully: result
message_iddescriptionUnknown errorTelegram API error: zHTTP error : HTTP zTelegram API request timed outz!Failed to send Telegram message: N)r   r   r(   r   r%   r   debugrequestspoststatus_coder6   r   errorRequestExceptionr2   Timeout)r   r+   r   r,   r-   target_chat_idurlpayloadresponser;   	error_msger    r    r!   send_messageN   sJ    




zTelegramService.send_messager   )
photo_pathcaptionr   r#   c              
   C   s6  |p| j }|std| j d}zt|d}d|i}||d}tj|||dd}	|	jdkr|	 }
|
d	r| j	
d
 |
W  5 Q R  W S |
dd}td| ntd|	j d|	j W 5 Q R X W n^ tk
r   | j	d|   Y n8 tk
r0 } z| j	d|   W 5 d}~X Y nX dS )a3  
        Send a photo with caption via Telegram.
        
        Args:
            photo_path (str): Path to the photo file
            caption (str): Photo caption text
            chat_id (str, optional): Target chat ID
            
        Returns:
            Dict[str, Any]: API response data
        r1   z
/sendPhotorbZphoto)r   rQ   <   )filesdatar7   r9   r:   z Telegram photo sent successfullyr=   r>   r?   rA   r@   zPhoto file not found: zFailed to send Telegram photo: N)r   r'   r   openrC   rD   rE   r6   r   r   r(   rG   r2   FileNotFoundErrorrF   	Exception)r   rP   rQ   r   rI   rJ   Z
photo_filerT   rU   rL   r;   rM   rN   r    r    r!   
send_photo   s2    


(zTelegramService.send_photo)jingle_name
similarityiframe_path
iframe_urldetection_timer#   c                 C   s*   d| d|dd| d| d| d 
S )a  
        Format a jingle detection message for Telegram.
        
        Args:
            jingle_name (str): Name of detected jingle
            similarity (float): Similarity score
            iframe_path (str): Path to extracted frame
            iframe_url (str): URL to view the frame
            detection_time (datetime): When detection occurred
            
        Returns:
            str: Formatted Telegram message
        u/   🎵 <b>Jingle Detected</b> 🎵

<b>Name:</b> z
<b>Similarity:</b> z.3fz
<b>Frame Path:</b> <code>z#</code>
<b>Frame URL:</b> <a href='z('>View Frame</a>
<b>Detection Time:</b> %Y-%m-%d %H:%M:%Sstrftime)r   rZ   r[   r\   r]   r^   r    r    r!   format_jingle_detection_message   s    (z/TelegramService.format_jingle_detection_messageF)channel_name
start_timeend_timedurationis_estimatedr#   c                 C   s`   |rD|rD|rdnd}d| d| d d| d d| d| d	S d
| d| d dS dS )a  
        Format an ad break message for Telegram.
        
        Args:
            channel_name (str): Name of the channel
            start_time (datetime): Ad break start time
            end_time (datetime, optional): Ad break end time
            duration (int, optional): Duration in seconds
            is_estimated (bool): Whether duration is estimated
            
        Returns:
            str: Formatted Telegram message
        Z	EstimatedZActualu4   🚨 <b>Ad Break Detected</b> 🚨

<b>Channel:</b> z
<b>Start Time:</b> r_   z
<b>End Time:</b> z
<b>z Duration:</b> z secondsu3   🔊 <b>Ad Break Started</b> 🔊

<b>Channel:</b> z
<b>Status:</b> In Progress...Nr`   )r   rc   rd   re   rf   rg   Zduration_typer    r    r!   format_ad_break_message   s    .	z'TelegramService.format_ad_break_message)NN)Nr*   T)r   N)NNF)__name__
__module____qualname____doc__r   strr"   r   boolr   r   rO   rY   floatr   rb   intrh   r    r    r    r!   r      sN      
N  
6"   r   c                   @   s>   e Zd ZdZdd Zdeeee ee ee edddZ	dS )	EmailServicez
    Service for sending email notifications.
    
    This service handles email delivery using Django's email framework
    with support for HTML templates and attachments.
    c                 C   s   t d| _dS )zInitialize the email service.zstream_processor.emailNr   r   r   r)   r    r    r!   r"     s    zEmailService.__init__N)subjectr+   
recipientshtml_message
from_emailr#   c              
   C   sr   z2t |||||dd}| jd| d |dkW S  tk
rl } z| jd|  W Y dS d}~X Y nX dS )a  
        Send an email notification.
        
        Args:
            subject (str): Email subject line
            message (str): Plain text message content
            recipients (List[str]): List of recipient email addresses
            html_message (str, optional): HTML message content
            from_email (str, optional): Sender email address
            
        Returns:
            bool: True if email was sent successfully
        F)rs   r+   rv   recipient_listru   fail_silentlyzEmail sent to z recipientsr   zFailed to send email: N)r
   r   r(   rX   rF   )r   rs   r+   rt   ru   rv   Z
sent_countrN   r    r    r!   
send_email  s    	
zEmailService.send_email)NN)
ri   rj   rk   rl   r"   rm   r   r   rn   ry   r    r    r    r!   rq     s   	  rq   c                   @   sF   e Zd ZdZdd Zd
eeeef eeeef  ee	e
ddd	ZdS )WebhookServicez
    Service for sending webhook notifications.
    
    This service handles HTTP webhook delivery with configurable
    endpoints, headers, and payload formats.
    c                 C   s   t d| _dS )zInitialize the webhook service.zstream_processor.webhooksNrr   r)   r    r    r!   r"   M  s    zWebhookService.__init__NPOSTr3   )rJ   rU   r8   methodr7   r#   c           	   
   C   s   zvddi}|r| | tj| ||||d}|jdkrR| jd|  W dS | jd|j d|j  W d	S W n@ t	k
r } z"| jd
| d|  W Y d	S d}~X Y nX dS )a  
        Send a webhook notification.
        
        Args:
            url (str): Webhook endpoint URL
            data (Dict[str, Any]): Data to send in the webhook
            headers (Dict[str, str], optional): HTTP headers
            method (str): HTTP method (POST, PUT, PATCH)
            timeout (int): Request timeout in seconds
            
        Returns:
            bool: True if webhook was sent successfully
        r4   r5   )r|   rJ   r6   r8   r7   )r9            zWebhook sent successfully to TzWebhook failed with status r@   FzFailed to send webhook to N)
updaterC   requestupperrE   r   r(   rF   r2   rX   )	r   rJ   rU   r8   r|   r7   Zwebhook_headersrL   rN   r    r    r!   send_webhookQ  s&    


zWebhookService.send_webhook)Nr{   r3   )ri   rj   rk   rl   r"   rm   r   r   r   rp   rn   r   r    r    r    r!   rz   E  s      
rz   c                   @   s   e Zd ZdZdd Zdeeeef ee ee e	dddZ
deeeef ee e	dd	d
Zee	dddZdeedddZdS )NotificationServicea
  
    Main notification service that coordinates different notification channels.
    
    This service provides a unified interface for sending notifications
    through various channels with automatic channel selection, template
    rendering, and retry logic.
    c                 C   s(   t d| _t | _t | _t | _dS )z$Initialize the notification service.zstream_processor.notificationsN)	r   r   r   r   telegramrq   emailrz   webhookr)   r    r    r!   r"     s    zNotificationService.__init__N)template_typecontextrc   	recipientr#   c           	   
   C   s   z~t jj|ddd}| s8| jd|  W dS d}|D ]4}| r@||r@| 	|||r@|d7 }|
  q@|dkW S  tk
r } z| jd|  W Y dS d	}~X Y nX d	S )
a  
        Send a notification using the specified template and context.
        
        Args:
            template_type (str): Type of notification template to use
            context (Dict[str, Any]): Template variables for rendering
            channel_name (str, optional): Specific channel to use
            recipient (str, optional): Specific recipient override
            
        Returns:
            bool: True if notification was sent successfully
        T)
event_type	is_activez	-priorityz,No notification rules found for event type: Fr   r   zFailed to send notification: N)r   objectsfilterorder_byexistsr   r%   can_triggercheck_conditions_send_rule_notificationmark_triggeredrX   rF   )	r   r   r   rc   r   rulesZsuccess_countrulerN   r    r    r!   send_notification  s(    

z%NotificationService.send_notification)r   r   r   r#   c           
   
   C   s   z|j |}|j |}|}|sn|jjdkr@|j d}n.|jjdkrn|j dg }|rj|d nd}|s| j	d|j
  W dS tjj|j|j ||||d	d
}| |W S  tk
r }	 z| j	d|	  W Y dS d}	~	X Y nX dS )al  
        Send a notification based on a specific rule.
        
        Args:
            rule (NotificationRule): Notification rule to apply
            context (Dict[str, Any]): Template rendering context
            recipient (str, optional): Recipient override
            
        Returns:
            bool: True if notification was sent successfully
        r   r   r   rt   r   Nz!No recipient available for rule: Fpending)channeltemplater   rs   r+   context_datar/   z"Failed to send rule notification: )r   render_subjectrender_messager   channel_typeget_telegram_configr   get_email_configr   rF   namer   r   create_deliver_notificationrX   )
r   r   r   r   rs   r+   Ztarget_recipientrt   notificationrN   r    r    r!   r     s4    z+NotificationService._send_rule_notification)r   r#   c              
   C   s  zN|j }|jdkr`| }| jj|j|jd}|di d}|j|rRt	|ndd W dS |jdkr| j
j|j|j|jgd	}|r|  W dS |d
 W dS n|jdkr"| }| jj|d|j|j|j|j d|di |ddd}|r|  W dS |d W dS n,| jd|j  |d|j  W dS W nR tk
r } z2| jd|j d|  |t	| W Y dS d}~X Y nX dS )z
        Deliver a notification via its configured channel.
        
        Args:
            notification (Notification): Notification to deliver
            
        Returns:
            bool: True if delivery was successful
        r   )r+   r   r;   r<   N)external_idTr   )rs   r+   rt   zEmail delivery failedFr   rJ   )rs   r+   r   	timestampr8   r|   r{   )rJ   rU   r8   r|   zWebhook delivery failedzUnsupported channel type: zFailed to deliver notification r@   )r   r   r   r   rO   r+   r   r   	mark_sentrm   r   ry   rs   mark_failedget_webhook_configr   r   r   scheduled_at	isoformatr   rF   rX   id)r   r   r   configr;   r<   successrN   r    r    r!   r     s\    







z)NotificationService._deliver_notification   )max_age_hoursr#   c                 C   sx   t  t|d }tjjd|d}d}|D ],}| r*d|_|  | 	|r*|d7 }q*|dkrt| j
d| d |S )	z
        Retry failed notifications that are eligible for retry.
        
        Args:
            max_age_hours (int): Maximum age of notifications to retry
            
        Returns:
            int: Number of notifications retried
        )hoursfailed)r/   created_at__gter   r   r   zRetried z failed notifications)r	   nowr   r   r   r   	can_retryr/   saver   r   r(   )r   r   cutoff_timefailed_notificationsretry_countr   r    r    r!   retry_failed_notifications?  s    


z.NotificationService.retry_failed_notifications)NN)N)r   )ri   rj   rk   rl   r"   rm   r   r   r   rn   r   r   r   r   r   rp   r   r    r    r    r!   r     s(     
2 
5Ir   )rl   rC   r6   timer   typingr   r   r   r   r   r   django.confr   django.utilsr	   django.core.mailr
   django.template.loaderr   modelsr   r   r   r   r   rq   rz   r   r    r    r    r!   <module>   s    	 x3<