
    Ѭi)                     v    S r SSKrSSKrSSKrSSKJrJrJr  \R                  " S5      r " S S5      r	Sq
S rg)a/  
Gmail morning briefing integration.

Pulls relevant email highlights for the dashboard morning briefing:
  - Unread count by category
  - Important/starred messages
  - Calendar invites and meeting-related emails
  - Actionable emails (flagged, needs reply)

Uses the Gmail API via google_auth module.
    N)datetimedate	timedeltazgmail-briefingc                   x    \ rS rSrSrS r\S 5       r\S 5       rS r	SS jr
SS jrSS	 jrS
 r\S 5       rSrg)GmailBriefing   z/Generate email briefing data for the dashboard.c                      S U l         S U l        g )N)_service
_availableselfs    5/Users/bsyrros/clawd/whatsapp-agent/gmail_briefing.py__init__GmailBriefing.__init__   s        c                     U R                   c   SSKJn  U" 5       U l         U R                   SLa  U R                   $ S$ ! [         a)  n[        R                  SU 35        SU l          SnANKSnAff = f)zLazy-load Gmail service.Nr   )build_gmail_servicezGmail service unavailable: F)r
   google_authr   	Exceptionloggerwarning)r   r   es      r   serviceGmailBriefing.service   sk     == &; 3 5 !%U :t}}DD  &!<QC@A %&s   > 
A1A,,A1c                     U R                   cZ  U R                  SLU l         U R                   (       a!  [        R                  S5        U R                   $ [        R                  S5        U R                   $ )z Check if Gmail API is available.NzGmail briefing: ACTIVEz5Gmail briefing: INACTIVE (Google auth not configured))r   r   r   infor   s    r   	availableGmailBriefing.available(   sW     ??""ll$6DO45  STr   c                    U R                   (       d  g SSSSS.n0 nSnUR                  5        Hd  u  pEU R                  R                  5       R	                  5       R                  SUS	S
9R                  5       nUR                  SS5      nXrU'   X7-  nMf     SU0UE$ ! [         a"  n[        R                  SU 35         SnAgSnAff = f)z
Get unread email summary by category.

Returns dict:
{
    "total_unread": int,
    "primary": int,
    "updates": int,
    "social": int,
    "promotions": int,
}
Nzis:unread category:primaryzis:unread category:updateszis:unread category:socialzis:unread category:promotions)primaryupdatessocial
promotionsr   me   userIdq
maxResultsresultSizeEstimatetotal_unreadzUnread summary failed: )r   itemsr   usersmessageslistexecutegetr   r   error)	r   
categoriescountstotalcatqueryresultcountr   s	            r   get_unread_summary GmailBriefing.get_unread_summary3   s     ~~	775=	J FE(..0
++-668==5Q > ')  

#7;#s 1  
  	LL21#67	s   BB 
C	'CC	c           
         U R                   (       d  / $  U R                  R                  5       R                  5       R	                  SSUS9R                  5       n/ nUR                  S/ 5       H  n U R                  R                  5       R                  5       R                  SUS   S/ SQS9R                  5       nUR                  S	0 5      R                  S
/ 5       Vs0 s H  nUS   US   _M     nnUR                  SS5      nU R                  U5      n	UR                  U	UR                  SS5      UR                  SS5      SS UR                  SS5      US   S.5        M     U$ s  snf ! [         a*  n
[        R                  SUS    SU
 35         Sn
A
GM2  Sn
A
ff = f! [         a$  n
[        R                  SU
 35        / s Sn
A
$ Sn
A
ff = f)z
Get recent important/starred unread emails.

Returns list of dicts:
[{"from": str, "subject": str, "snippet": str, "date": str}, ...]
r$   zLis:unread (is:important OR is:starred) -category:promotions -category:socialr&   r.   idmetadataFromSubjectDater'   r=   formatmetadataHeaderspayloadheadersnamevaluer@   UnknownrA   (no subject)snippet Nx   rB   )fromsubjectrL   r   r=   zFailed to fetch message : zImportant emails fetch failed: )r   r   r-   r.   r/   r0   r1   _clean_fromappendr   r   debugr2   )r   max_resultsr8   r.   msg_refmsghrG   from_raw
from_cleanr   s              r   get_important_emails"GmailBriefing.get_important_emails^   s    ~~I*	\\'')22499`& :  gi	  H!::j"5,,,,.779==#"4=)(C	 > 
 gi  "%B!7!;!;Ir!J!JA &	1W:-!J    '{{69=H!%!1!1(!;JOO *#*;;y.#I#&779b#9$3#? 'FB 7%dm% % 6: O)  ! LL#;GDM?"QC!PQ  	LL:1#>?I	s\   AF( 2A/E1!E,4A2E1&F( ,E11
F%;F F(  F%%F( (
G2GGGc           	         U R                   (       d  / $  [        R                  " 5       nUR                  S5      nU[	        US-   S9-   R                  S5      nU R
                  R                  5       R                  5       R                  SSU SU 3SS9R                  5       n/ nUR                  S	/ 5       H  n U R
                  R                  5       R                  5       R                  SUS
   S/ SQS9R                  5       nUR                  S0 5      R                  S/ 5       V	s0 s H  n	U	S   U	S   _M     n
n	UR                  U R                  U
R                  SS5      5      U
R                  SS5      UR                  SS5      SS S.5        M     U$ s  sn	f ! [         a     M  f = f! [         a$  n[        R                  SU 35        / s SnA$ SnAff = f)zp
Get emails with calendar invites or meeting-related content.

Returns list of meeting-related email summaries.
z%Y/%m/%dr%   )daysr$   zI(has:attachment filename:ics OR subject:invite OR subject:meeting) after:z before:
   r&   r.   r=   r>   r?   rC   rF   rG   rH   rI   r@   rM   rA   zMeeting inviterL   Nd   rO   rP   rL   zMeeting emails fetch failed: )r   r   todaystrftimer   r   r-   r.   r/   r0   r1   rS   rR   r   r   r2   )r   
days_aheadrb   
after_datebefore_dater8   meetingsrV   rW   rX   rG   r   s               r   get_meeting_emails GmailBriefing.get_meeting_emails   s    ~~I'	JJLE
3J 9*q.#AAKKJWK\\'')22499]^h]iiqr}q~ :  gi	  H!::j"5,,,,.779==#"4=)(C	 > 
 gi  "%B!7!;!;Ir!J!JA &	1W:-!J  
 OO $ 0 0VR1H I#*;;y:J#K#&779b#9$3#?%  6, O ! 
  	LL8<=I	sV   B&F3 <A/F"+F>AF"F3 F""
F0,F3 /F00F3 3
G!=GG!G!c           	      4   U R                   (       d  / $  U R                  R                  5       R                  5       R	                  SSUS9R                  5       n/ nUR                  S/ 5       H  n U R                  R                  5       R                  5       R                  SUS   SSS/S	9R                  5       nUR                  S
0 5      R                  S/ 5       Vs0 s H  nUS   US   _M     nnUR                  U R                  UR                  SS5      5      UR                  SS5      UR                  SS5      SS S.5        M     U$ s  snf ! [         a     M  f = f! [         a$  n[        R                  SU 35        / s SnA$ SnAff = f)zj
Get emails that likely need a reply (sent directly to Bill,
from real people, unread, in primary inbox).
r$   zQis:unread category:primary to:me -from:noreply -from:no-reply -from:notificationsr&   r.   r=   r>   r@   rA   rC   rF   rG   rH   rI   rM   rK   rL   Nr`   ra   zNeeds-reply fetch failed: )r   r   r-   r.   r/   r0   r1   rS   rR   r   r   r2   )	r   rU   r8   emailsrV   rW   rX   rG   r   s	            r   get_needs_replyGmailBriefing.get_needs_reply   s   
 ~~I"	\\'')22499e& :  gi	  F!::j"5,,,,.779==#"4=))/(;	 > 
 gi  "%B!7!;!;Ir!J!JA &	1W:-!J  
 MM $ 0 0VR1H I#*;;y.#I#&779b#9$3#?#  6, M ! 
  	LL5aS9:I	sV   AE) 2A/E!E4AEE) E
E&"E) %E&&E) )
F3FFFc           	         U R                   (       d  SS0$  U R                  5       nU R                  S5      nU R                  S5      nU R	                  S5      n/ nU(       a"  US   nUS   nUR                  SU S	U S
35        U(       aG  UR                  S[        U5       S35        U H#  nUR                  SUS    SUS   SS  35        M%     U(       aQ  U(       dJ  UR                  S[        U5       S35        USS  H#  nUR                  SUS    SUS   SS  35        M%     U(       a  UR                  S[        U5       35        SUUUUU(       a  SR                  U5      OS[        R                  " 5       R                  5       S.$ ! [         a0  n[        R                  SU 35        S[        U5      S.s SnA$ SnAff = f)z
Generate a complete email briefing for the morning card.

Returns dict:
{
    "available": bool,
    "unread": {...},
    "important": [...],
    "needs_reply": [...],
    "meetings": [...],
    "summary_text": str,
}
r   F      r%   r+   r    zInbox: z	 unread (z	 primary)zNeeds reply (z):u     — rO   rQ   rP   N2   zImportant (zMeeting invites: T
zInbox clear!)r   unread	importantneeds_replyrg   summary_text	generatedzBriefing generation failed: )r   r2   )r   r:   r[   rl   rh   rS   lenjoinr   now	isoformatr   r   r2   str)	r   rs   rt   ru   rg   linesr5   r    r   s	            r   generate_briefingGmailBriefing.generate_briefing   s    ~~''&	9,,.F11!4I..q1K..q1H E~. +wugYwiyIJ}S-=,>bAB$ALL6!F)Bq|CR7H6I!JK % {3y>*:"=>"2AALL6!F)Bq|CR7H6I!JK ' 0X@A " &*$49		% 0~%\\^557   	9LL7s;<!&Q88	9s   E:F 
G%GGGc                     [         R                  " SU 5      nU(       a  UR                  S5      R                  5       $ [         R                  " SU 5      nU(       a  UR                  S5      $ U R                  5       $ )z*Extract clean name from email From header.z^"?([^"<]+)"?\s*<r%   z<(.+)>)rematchgroupstrip)rY   r   s     r   rR   GmailBriefing._clean_from+  s]     -x8;;q>''))H-;;q>!~~r   )r   r
   N)ro   )r%   )rp   )__name__
__module____qualname____firstlineno____doc__r   propertyr   r   r:   r[   rh   rl   r~   staticmethodrR   __static_attributes__ r   r   r   r      sf    9 	E 	E  )V4l0d*X79r 
  
 r   r   c                  0    [         c
  [        5       q [         $ )z)Get the singleton GmailBriefing instance.)	_briefingr   r   r   r   get_gmail_briefingr   =  s     !O	r   )r   loggingbase64r   r   r   r   	getLoggerr   r   r   r   r   r   r   <module>r      sE   
   	 . .			+	,a  a J	 	r   