
    %{j*                       d Z ddlmZ ddlZddlZddlZddlZddlZddlmZm	Z	 ddl
mZ ddlmZmZ ddlmZ  ej"                  d      Z ee      j)                         j*                  Zed	z  Z ed
      Z e ej4                  d ed                  Z e ej4                  d ed                  Z e ej4                  dd            Z e ej4                  dd            Z e ej4                  dd            Z  G d d      Z!y)a
  
Follow-up automatico para o SDR Gi (Sweet Angels / Medio Porte Sorocaba).

Regras:
  - 1h sem resposta apos ultima msg outbound da Gi -> follow-up leve.
  - 24h sem resposta apos o follow-up de 1h -> segunda tentativa.
  - Nao envia se conversa foi encerrada (tag [[QUALIFICADO]] ou @sweetangelsgastronomia na ultima msg da Gi).
  - Somente em horario comercial (08h-20h America/Sao_Paulo).
  - Reset do estado a cada resposta nova do lead.
  - Maximo 2 follow-ups por conversa.

State persistido em followup_state.json.
    )annotationsN)datetime	timedelta)Path)AnyCallable)ZoneInfofollowup_manager_medio_portezfollowup_state.jsonzAmerica/Sao_PauloSDR_FOLLOWUP_1H_SECONDSi  SDR_FOLLOWUP_24H_SECONDSiQ SDR_FOLLOWUP_CHECK_INTERVAL60SDR_FOLLOWUP_HOUR_START8SDR_FOLLOWUP_HOUR_END20c                      e Zd Z	 d	 	 	 	 	 	 	 ddZddZddZ	 d	 	 	 	 	 ddZddZddZddZ	dd	Z
dd
ZddZdddZddZddZy)FollowupManagerNc                    || _         || _        || _        || _        i | _        t        j                         | _        d| _        t        j                         | _
        | j                          y)a!  
        send_fn(contact_id, message, conversation_id) -> (ok, status, body)
        generate_followup_fn(contact_id, tipo) -> str, tipo in ("1h", "24h")
        is_encerrada_fn(contact_id) -> bool
        on_conversation_closed_fn(contact_id) -> None  (chamada apos followup 24h)
        N)send_fngenerate_followup_fnis_encerrada_fnon_conversation_closed_fn_state	threadingLock_lock_threadEvent_stop_event_load_state)selfr   r   r   r   s        L/opt/mia/workspace/clientes/sweet_angels/sdr_medio_porte/followup_manager.py__init__zFollowupManager.__init__*   sZ     $8!.)B&13^^%
04$??,    c                   t         j                         si | _        y 	 t        j                  t         j                  d            }t        |t              r1|| _        t        j                  dt        | j                               y i | _        y # t        j                  t        f$ r'}t        j                  d|       i | _        Y d }~y d }~ww xY w)Nutf-8encodingz%followup state carregado: %d contatosz!state corrompido, recomecando: %s)
STATE_PATHexistsr   jsonloads	read_text
isinstancedictloginfolenJSONDecodeErrorOSErrorwarning)r"   rawes      r#   r!   zFollowupManager._load_stateE   s      "DK		**Z1171CDC#t$!@#dkkBRS $$g. 	KK;Q?DKK	s   A)B B C)CCc                    	 t         j                  t        j                  | j                  dd      d       y # t
        $ r }t        j                  d|       Y d }~y d }~ww xY w)NF   )ensure_asciiindentr'   r(   znao consegui salvar state: %s)r*   
write_textr,   dumpsr   r5   r1   r6   r"   r8   s     r#   _save_state_lockedz"FollowupManager._save_state_lockedT   sU    	<!!

4;;U1E  "   	<KK7;;	<s   7: 	A#AA#c                   t        j                          }| j                  5  | j                  j                  |i       }||d<   |j                  d      sd|d<   d|d<   d|d<   |r||d<   |j	                  dd       || j                  |<   | j                          ddd       t        j                  d	|       y# 1 sw Y    xY w)
z3Chamado apos a Gi enviar uma msg outbound pro lead.last_outboundfollowup_1h_sentFfollowup_24h_sentNfollowup_1h_atconversation_id	encerradoz"registrada msg outbound contact=%s)timer   r   get
setdefaultr@   r1   r2   )r"   
contact_idrF   nowentrys        r#   registrar_mensagem_enviadaz*FollowupManager.registrar_mensagem_enviada`   s     iikZZ 	&KKOOJ3E%(E/" 99/0,1()-2)**.&'+:'([%0&+DKK
###%	& 	5zB	& 	&s   A:B::Cc                *   | j                   5  | j                  j                  |      }|s
	 ddd       y|j                  d      sd|d<   d|d<   d|d<   d|d<   | j                          ddd       t        j                  d|       y# 1 sw Y    xY w)z)Chamado quando o lead responde (inbound).NrC   FrD   rE   rB   zlead respondeu contact=%sr   r   rI   r@   r1   r2   r"   rK   rM   s      r#   registrar_resposta_recebidaz+FollowupManager.registrar_resposta_recebidaw   s    ZZ 
	&KKOOJ/E
	& 
	&
 99/0,1()-2)**.&')-o&##%
	& 	,j9
	& 
	&s   B	5B		Bc                    | j                   5  | j                  j                  |i       }d|d<   || j                  |<   | j                          d d d        t        j                  d|       y # 1 sw Y    xY w)NTrG   z*conversa marcada como encerrada contact=%srP   rQ   s      r#   marcar_encerradoz FollowupManager.marcar_encerrado   sg    ZZ 	&KKOOJ3E!%E+&+DKK
###%		&
 	=zJ	& 	&s   AA--A6c                    |sy | j                   5  | j                  j                  |i       }||d<   || j                  |<   | j                          d d d        y # 1 sw Y   y xY w)NrF   )r   r   rI   r@   )r"   rK   rF   rM   s       r#   set_conversation_idz#FollowupManager.set_conversation_id   s]    ZZ 	&KKOOJ3E'6E#$&+DKK
###%		& 	& 	&s   AAA#c                ^   | j                   r| j                   j                         ry | j                  j                          t	        j
                  | j                  dd      }|| _         |j                          t        j                  dt        t        t        t        j                         y )Nzfollowup-loopT)targetnamedaemonz9followup loop iniciado (check %ds, janela %02dh-%02dh %s))r   is_aliver    clearr   Thread	_run_loopstartr1   r2   CHECK_INTERVAL_SECONDSBUSINESS_HOUR_STARTBUSINESS_HOUR_ENDTZkey)r"   ts     r#   r_   zFollowupManager.start   st    <<DLL113 DNNQUV		G"$79JBFF	
r%   c                8    | j                   j                          y N)r    set)r"   s    r#   stopzFollowupManager.stop   s    r%   c                (   | j                   j                         sL	 | j                          | j                   j                  t               | j                   j                         sKy y # t        $ r }t        j                  d|       Y d }~`d }~ww xY w)Nzerro no tick do followup: %s)r    is_set_tick	Exceptionr1   	exceptionwaitr`   r?   s     r#   r^   zFollowupManager._run_loop   st    ""))+A

 !!"89 ""))+  A<a@@As   A( (	B1BBc                    t        j                  |xs t        j                         t              }t        |j
                  cxk  xr	 t        k  S c S rg   )r   fromtimestamprH   rc   ra   hourrb   )r"   now_tsdts      r#   _is_business_hourz!FollowupManager._is_business_hour   s:    ##F$9diik2>"bggA0AAAAAr%   c                @   t        j                          }| j                  5  t        | j                  j	                               }d d d        D ]  \  }}|j                  d      r|j                  d      }|s-	 | j                  |      r| j                  |       Q	 | j                  |      sd||z
  }|j                  d      s|t        k\  r| j                  |d       |j                  d      }|j                  d      xs d}t        |xs d|      }	|j                  d      s|j                  d      r|	s||	z
  t        k\  s| j                  |d	        y # 1 sw Y   #xY w# t        $ r!}t        j                  d||       Y d }~d }~ww xY w)
NrG   rB   z*falha checando encerramento contact=%s: %srC   1hrE   r   rD   24h)rH   r   listr   itemsrI   r   rT   rm   r1   r6   ru   FOLLOWUP_1H_SECONDS_send_followupmaxFOLLOWUP_24H_SECONDS)
r"   rL   snapshotrK   rM   rB   r8   elapsedrE   ref_24hs
             r#   rl   zFollowupManager._tick   s   iik ZZ 	1DKK--/0H	1 "* (	Jyy%!IIo6M Y''
3))*5 4 ))#.M)G II0122##J5 #YY'78N!IIo6;!M.-A}=G		,-		"567]';;##J6Q(		1 	1   YH*VWXXYs#   $E&="E3&E03	F<FFc                    | j                   5  | j                  j                  |      }|s
	 d d d        y |j                  d      }d d d        t        j	                  d||       	 | j                  ||      }|r|j                         st        j                  d||       y |j                  d      D cg c]#  }|j                         s|j                         % }}d}	t        |      D ]f  \  }
}|
dkD  rt        j                  d       | j                  ||      \  }}}t        j	                  d	||
d
z   t        |      ||||d d        |red}	h |	st        j                  d||       t        j                         }| j                   5  | j                  j                  |i       }|dk(  rd|d<   ||d<   n|dk(  r
d|d<   d|d<   || j                  |<   | j!                          d d d        |dk(  r | j"                  r	 | j#                  |       y y y # 1 sw Y   xY w# t        $ r"}t        j                  d|||       Y d }~y d }~ww xY wc c}w # 1 sw Y   oxY w# t        $ r!}t        j                  d||       Y d }~y d }~ww xY w)NrF   zgerando followup %s contact=%sz(falha gerando followup %s contact=%s: %szfollowup %s vazio contact=%sz	[[BREAK]]Tr   r:   z=followup %s bloco %d/%d contact=%s ok=%s status=%s preview=%r   P   Fz%followup %s parcial/falhou contact=%srw   rC   rE   rx   rD   rG   z/on_conversation_closed_fn falhou contact=%s: %s)r   r   rI   r1   r2   r   rm   rn   stripr6   split	enumeraterH   sleepr   r3   r@   r   )r"   rK   tiporM   rF   mensagemr8   bblocosall_okiblocookstatus_bodyrL   s                   r#   r|   zFollowupManager._send_followup   sp   ZZ 	;KKOOJ/E	; 	; $ii(9:O		; 	14D	00TBH
 x~~/KK6jI &.^^K%@NAGGI!'')NN!&) 		HAu1u

1 $Z PBHHOa!eS[*b&%* 		 KK?zR iikZZ 		&KKOOJ3Et|,0()*-&'-1)*%)k"&+DKK
###%		& 5=T;;`..z: <=_	; 	;  	MMDdJXYZ	 O$		& 		&  `OQ[]^__`sY   HH&H$ 5IIAII# H!$	I-I

II #	J,JJrg   )r   z7Callable[[str, str, str | None], tuple[bool, int, str]]r   zCallable[[str, str], str]r   zCallable[[str], bool]r   zCallable[[str], None] | None)returnNone)rK   strrF   z
str | Noner   r   )rK   r   r   r   )rs   zfloat | Noner   bool)rK   r   r   r   r   r   )__name__
__module____qualname__r$   r!   r@   rN   rR   rT   rV   r_   ri   r^   ru   rl   r|    r%   r#   r   r   )   s     CGH 8 /	
 $@6< '+CC $C 
	C.:K&

:B/b4`r%   r   )"__doc__
__future__r   r,   loggingosr   rH   r   r   pathlibr   typingr   r   zoneinfor	   	getLoggerr1   __file__resolveparentBASE_DIRr*   rc   intgetenvr   r{   r~   r`   ra   rb   r   r   r%   r#   <module>r      s    #   	   (    g67>!!#**--
!")"))$=s7|LM 9299%?\ARST YRYY'DdKL )"))$=sCD 			"94@A u` u`r%   