a
    9.j1                     @   s   d dl Z d dlZd dlZd dlZd dlmZ dZdddddd	Zd
d Zdd Z	dd Z
d3ddZdd Zdd Zdd Zd4ddZdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd5d/d0Zd1d2 ZdS )6    N)datetimez/var/www/html/chat.logZ	localhostZwhatsapp_userz
@dlkobs901Zwhatsapp_atendimento_hibridoZutf8mb4)ZhostuserZpasswordZdatabasecharsetc                   C   s   t jjf i tS )u:   Retorna uma nova conexão ativa com a base de dados MySQL.)mysqlZ	connectorZconnect	DB_CONFIG r   r   /var/www/html/utils_hibrido.pyobter_conexao   s    r	   c              
   C   s   t  d}d| d|   d| }t| z@ttddd}||d  W d	   n1 sd0    Y  W n6 ty } ztd
t	|  W Y d	}~n
d	}~0 0 d	S )uL   Grava as ações centralizadamente no arquivo chat.log e espelha no console.z%Y-%m-%d %H:%M:%S[z] [z] azutf-8)encoding
Nu   ❌ Erro ao escrever log: )
r   ZnowstrftimeupperprintopenLOG_FILE_PATHwrite	Exceptionstr)ZorigemmensagemZ	timestampZ	log_linhafer   r   r   registrar_log   s    0r   c                 C   s   | sdS t dd| S )uC   Filtra o input do cliente mantendo apenas os caracteres numéricos. z\D)resub)textor   r   r   limpar_cpf_cnpj#   s    r   r   c              
   C   st   z0|  d|f |  }|r.|d r.|d W S W n> tyn } z&tdd| dt|  W Y d}~n
d}~0 0 |S )zSRecupera dinamicamente as respostas configuradas na tabela robot_prompts_mensagens.z=SELECT conteudo FROM robot_prompts_mensagens WHERE chave = %sZconteudoSYSTEM_ERRORzErro ao ler mensagem 'z': N)executefetchoner   r   r   )cursorchaveZfallbackresultr   r   r   r   obter_mensagem_db)   s    0r%   c                 C   s&   |  d|f |  }|r"|d S dS )u7   Busca uma configuração específica no banco de dados.z1SELECT valor FROM config_sistema WHERE chave = %svalorN)r    r!   )r"   r#   resr   r   r   buscar_config4   s    r(   c           
   
   C   s   |  d}|  d}|r|s*tdd dS d| d}d| d	d
}d|dd|id}z`tj|||dd}|jdkrtdd| d W dS tdd|j d|jdd   W dS W n< t y }	 z"tddt|	  W Y d}	~	dS d}	~	0 0 dS )zGEfetua o envio de mensagens de texto via API Cloud oficial do WhatsApp.ZWHATSAPP_TOKENZPHONE_NUMBER_IDr   zEFalha ao enviar WhatsApp: WHATSAPP_TOKEN ou PHONE_NUMBER_ID ausentes.Fz!https://graph.facebook.com/v25.0/z	/messagesBearer application/jsonZAuthorizationContent-TypeZwhatsapptextbody)Zmessaging_producttotyper-      jsonheaderstimeout   ZWHATSAPP_APIu&   ✔ Mensagem enviada com sucesso para .Tu   ❌ Erro de envio (): Nu   Exceção ao enviar mensagem: )getr   requestspoststatus_coder-   r   r   )
configsZnumeror   ZtokenZphone_idurlr4   payloadresponser   r   r   r   enviar_whatsapp:   s0    



"
rA   c              
   C   s*  |  d}|  d}|r|s*tdd dS d| dd}d	d
|dd|dgdddid}ztj|||dd}|jdkr| }|d d d d  }	tdd|	dd   t|	W S tdd|j d|jdd   W dS W n< t	y$ }
 z"tddt
|
  W Y d}
~
dS d}
~
0 0 dS )zNConsulta a API do DeepSeek retornando estritamente um objeto JSON estruturado.ZDEEPSEEK_API_KEYZDEEPSEEK_API_URLZIA_CLASSIFIERu-   Credenciais da API DeepSeek não encontradas.Nr)   r*   r+   zdeepseek-chatsystem)Zrolecontentr   g        r0   Zjson_object)ZmodelZmessagesZtemperatureZresponse_format   r2   r6   Zchoicesr   messagerC   zResposta da IA: u   Erro na requisição (r8   u!   Exceção ao consultar DeepSeek: )r9   r   r:   r;   r<   r3   striploadsr-   r   r   )r=   Zmensagem_usuarioZprompt_sistemaapi_keyZapi_urlr4   r?   r@   	resultadoZretorno_textor   r   r   r   consultar_deepseek[   s6    




"
rJ   GETc              
      s  t | d}t | d}|r|s0tdd dddS |d  }|rx| D ],\}}d	| d
 }	|	|v rJ||	t|}qJ|dd}
tdd| d|  z|dkrtj||
dd}n|dkr|r؇ fdd| D ni }tj|||
dd}nR|dkr.|r fdd| D ni }tj	|||
dd}ndd| ddW S tdd|j
  |j
dkrpd| dW S tdd|j
 d|jd d!   dd"|j
 |jd#W S W nH ty } z.tdd$t|  dt|dW  Y d }~S d }~0 0 d S )%um  
    Chama a API RadiusNet usando as configurações do banco.
    
    Args:
        cursor: cursor do banco de dados
        endpoint: string do endpoint (ex: '/cp/{cpf}/2')
        params: dict com parâmetros para substituir na URL
        metodo: 'GET', 'POST' ou 'PUT'
    
    Returns:
        dict: {'success': bool, 'data': dict ou list, 'error': str}
    ZRADIUSNET_API_URLZRADIUSNET_API_KEY	RADIUSNETu.   Credenciais não encontradas no config_sistemaFu   Credenciais não configuradas)successerror/{}r*   )ZRTOKENr,   zChamando API:  rK   r1   )r4   r5   POSTc                    s&   i | ]\}}d | d vr||qS rP   rQ   r   .0kvendpointr   r   
<dictcomp>       z(chamar_api_radiusnet.<locals>.<dictcomp>r2   PUTc                    s&   i | ]\}}d | d vr||qS rT   r   rU   rY   r   r   r[      r\   u   Método u    não suportadozResposta HTTP: r6   T)rM   dataz
Erro HTTP z: Ni  zHTTP )rM   rN   Zdetailsu   Exceção: )r(   r   rstripitemsreplacer   r:   r9   r;   Zputr<   r3   r-   r   )r"   rZ   paramsmetodoZbase_urlrH   r>   keyvalueZplaceholderr4   Zrespr.   r   r   rY   r   chamar_api_radiusnet   sB    




 "rf   c                 C   s   d}d|i}t | ||dd}|dr|d }t|trfd|v rftdd	|d
d d|  |d S t|trtdd	t| d|  |S tddt|  g S ntdd|d  g S dS )z
    Busca cliente por CPF.
    Endpoint: GET /cp/{cpf}/2
    Retorna lista de cadastros (extrai do campo 'rows' da resposta)
    z/cp/{cpf}/2cpfrK   rc   rM   r^   rowsrL   zEncontrados countr   z cadastros para CPF z"Estrutura de resposta inesperada: zErro na consulta: rN   N)rf   r9   
isinstancedictr   listlenr0   )r"   rg   rZ   rb   rI   r^   r   r   r   consultar_cliente_por_cpf   s    

ro   c                 C   sP   d}d|i}t | ||dd}|drL|d }t|trHd|v rH|d S |S dS )	z
    Busca dados completos do cliente por ID.
    Endpoint: GET /cpcd/cli/{id_cliente}
    Retorna: dados do cliente incluindo emails e telefones
    z/cpcd/cli/{id_cliente}
id_clienterK   rh   rM   r^   ri   N)rf   r9   rk   rl   )r"   rp   rZ   rb   rI   r^   r   r   r   consultar_cliente_por_id   s    
rq   c                 C   s2   d}d|i}t | ||dd}|dr.|d S g S )uW   
    Busca cobranças em atraso do cliente.
    Endpoint: GET /cbc/at/{id_cliente}
    z/cbc/at/{id_cliente}rp   rK   rh   rM   r^   rf   r9   r"   rp   rZ   rb   rI   r   r   r   cobrancas_cliente_atraso   s    
rt   c                 C   s2   d}d|i}t | ||dd}|dr.|d S g S )uu   
    Busca cobranças não pagas do cliente (inclui vencidas e a vencer).
    Endpoint: GET /cbc/np/{id_cliente}
    z/cbc/np/{id_cliente}rp   rK   rh   rM   r^   rr   rs   r   r   r   cobrancas_cliente_nao_pagas   s    
ru   c                 C   s2   d}d|i}t | ||dd}|dr.|d S g S )uj   
    Busca cobranças em atraso de um plano específico.
    Endpoint: GET /cbp/at/{id_cliente_plano}
    z/cbp/at/{id_cliente_plano}id_cliente_planorK   rh   rM   r^   rr   r"   rv   rZ   rb   rI   r   r   r   cobrancas_plano_atraso  s    
rx   c                 C   s2   d}d|i}t | ||dd}|dr.|d S g S )uk   
    Busca cobranças não pagas de um plano específico.
    Endpoint: GET /cbp/np/{id_cliente_plano}
    z/cbp/np/{id_cliente_plano}rv   rK   rh   rM   r^   rr   rw   r   r   r   cobrancas_plano_nao_pagas  s    
ry   c                 C   s2   d}d|i}t | ||dd}|dr.|d S dS )zi
    Gera URL do boleto PDF.
    Endpoint: GET /bc/{id_cobranca}
    Retorna: {'url': 'https://...'}
    z/bc/{id_cobranca}id_cobrancarK   rh   rM   r^   Nrr   r"   rz   rZ   rb   rI   r   r   r   gerar_boleto(  s    
r|   c                 C   s2   d}d|i}t | ||dd}|dr.|d S dS )uR   
    Solicita desbloqueio em confiança.
    Endpoint: PUT /ppg/{id_cobranca}
    z/ppg/{id_cobranca}rz   r]   rh   rM   r^   Nrr   r{   r   r   r   desbloquear_confianca7  s    
r}   c                 C   s*   d}||d}t | ||dd}|ddS )zz
    Adiciona novo e-mail ao cadastro.
    Endpoint: POST /adicemail/
    Body: {"IDCLI": id_cliente, "EMAIL": email}
    z/adicemail/)IDCLIZEMAILrS   rh   rM   Frr   )r"   rp   ZemailrZ   rb   rI   r   r   r   atualizar_emailE  s    
r      c                 C   s.   d}||||d}t | ||dd}|ddS )z
    Adiciona novo telefone ao cadastro.
    Endpoint: POST /ct/
    Body: {"IDCLI": id_cliente, "DDD": ddd, "TEL": telefone, "TT": tipo}
    Tipos: 1-Residencial, 2-Celular, 3-Comercial
    z/ct/)r~   ZDDDZTELZTTrS   rh   rM   Frr   )r"   rp   ZdddZtelefoneZtiporZ   rb   rI   r   r   r   atualizar_telefoneQ  s    r   c                 C   s2   d}d|i}t | ||dd}|dr.|d S dS )uX   
    Verifica se o cliente está online (conectado).
    Endpoint: GET /cpl/{login}
    z/cpl/{login}loginrK   rh   rM   r^   Nrr   )r"   r   rZ   rb   rI   r   r   r   verificar_status_online^  s    
r   )r   )NrK   )r   )r3   r   r:   Zmysql.connectorr   r   r   r   r	   r   r   r%   r(   rA   rJ   rf   ro   rq   rt   ru   rx   ry   r|   r}   r   r   r   r   r   r   r   <module>   s<   
!+
<
