o
    ŸÁŠiç2  ã                   @   sz   d Z ddlZddlmZ ddlZddlmZmZmZ ddl	m	Z	 ddl
mZ ddlmZ e e¡ZG dd	„ d	ƒZeƒ ZdS )
zm
Bot Configuration Service for MCube Voice Bot
Handles dynamic bot configuration based on DID number mapping
é    N)ÚError)ÚOptionalÚDictÚAny)Údatetime)ÚConfig)ÚLogc                	   @   sì   e Zd ZdZdd„ Zddefdd„Zded	ee fd
d„Z	defdd„Z
ded	ee fdd„Zdeded	eeeef  fdd„Zded	eeef fdd„Zdeded	eeeef  fdd„Zded	ee fdd„Zd	eeef fdd„ZdS )ÚBotConfigurationServicezž
    Service for managing dynamic bot configurations based on DID number mapping.
    Maps DID numbers to specific bot configurations stored in database.
    c                 C   sH   t jdt jt jt jddœ| _t jt jt jt jt jddœ| _t 	d¡ d S )NÚmainvoicebot_masterT)ÚhostÚdatabaseÚuserÚpasswordÚcharsetÚ
autocommitu*   ðŸ¤– Bot Configuration Service initialized)
r   ÚDATABASE_HOSTÚDATABASE_USERÚDATABASE_PASSWORDÚDATABASE_CHARSETÚmaster_db_configÚDATABASE_NAMEÚcluster_db_configr   Úinfo)Úself© r   úG/var/www/html/live_calls/homebook/services/bot_configuration_service.pyÚ__init__   s   úú	z BotConfigurationService.__init__ÚclusterÚdatabase_typec              
   C   s^   z|dkr| j n| j}tjjdi |¤Ž}|W S  ty. } zt d|› d|› ¡ ‚ d}~ww )zÏ
        Get database connection for master or cluster database.
        
        Args:
            database_type: 'master' or 'cluster'
            
        Returns:
            Database connection
        Úmasteru   âŒ Error connecting to z database: Nr   )r   r   ÚmysqlÚ	connectorÚconnectr   r   Úerror)r   r   ÚconfigÚ
connectionÚer   r   r   Úget_connection,   s   
€þz&BotConfigurationService.get_connectionÚ
did_numberÚreturnc           	   
   C   s<  d}d}z‹z]|   d¡}|jdd}d}| ||f¡ | ¡ }|rI|d }|d }t d|› d	|› d
|› ¡ ||fW W |rA| ¡  |rH| ¡  S S t d|› ¡ W W |rY| ¡  |ra| ¡  dS dS  ty } z!t 	d|› d|› ¡ W Y d}~W |r| ¡  |r‰| ¡  dS dS d}~ww |r–| ¡  |r| ¡  w w )zÖ
        Get bot_id from DID number mapping in master database.
        
        Args:
            did_number: DID number to lookup
            
        Returns:
            bot_id if found, None otherwise
        Nr   T©Ú
dictionaryz‚
            SELECT bot_id, business_id 
            FROM did_numbers 
            WHERE did_no = %s AND status = '1'
            Úbot_idÚbusiness_idu   ðŸ” Found bot mapping - DID: z
, Bot ID: z, Business ID: õ%   âš ï¸ No bot mapping found for DID: )NNu   âŒ Error looking up DID ú: ©
r'   ÚcursorÚexecuteÚfetchoner   r   ÚcloseÚwarningr   r#   )	r   r(   r%   r1   ÚqueryÚresultr,   r-   r&   r   r   r   Úget_bot_id_by_did>   sP   


	
ÿ÷ÿúÿ€ú
ÿz)BotConfigurationService.get_bot_id_by_didc                 ƒ   ó2   ddl }‡ ‡fdd„}| ¡ }| d|¡I dH S )z5Async version of get_bot_id_by_did using thread pool.r   Nc                      ó
   ˆ  ˆ ¡S ©N)r8   r   ©r(   r   r   r   Ú_sync_get_bot_idn   ó   
zIBotConfigurationService.get_bot_id_by_did_async.<locals>._sync_get_bot_id©ÚasyncioÚget_event_loopÚrun_in_executor)r   r(   r@   r=   Úloopr   r<   r   Úget_bot_id_by_did_asyncj   s
   €z/BotConfigurationService.get_bot_id_by_did_asyncr-   c              
   C   s*  d}d}z‚zT|   d¡}|jdd}d}| ||f¡ | ¡ }|r@|d }t d|› d|› ¡ |W W |r8| ¡  |r?| ¡  S S t d	|› ¡ W W |rP| ¡  |rX| ¡  dS dS  ty† } z!t 	d
|› d|› ¡ W Y d}~W |rx| ¡  |r€| ¡  dS dS d}~ww |r| ¡  |r”| ¡  w w )zâ
        Get business name from business table in master database.
        
        Args:
            business_id: Business ID to lookup
            
        Returns:
            Business name if found, None otherwise
        Nr   Tr*   z…
            SELECT business_name 
            FROM businesses 
            WHERE business_id = %s AND status = 'active'
            Úbusiness_nameu(   ðŸ¢ Found business name - Business ID: z, Name: u*   âš ï¸ No business found for Business ID: u   âŒ Error looking up business r/   r0   )r   r-   r%   r1   r6   r7   rE   r&   r   r   r   Úget_business_name_by_idt   sN   

	
ÿ÷ÿúÿ€ú
ÿz/BotConfigurationService.get_business_name_by_idr,   c           
   
   C   sP  d}d}z•zg|   d¡}|jdd}|› d}d|› d}| ||f¡ | ¡ }|rS|d |d	 |d
 dœ}t d|d	 › d|› ¡ |W W |rK| ¡  |rR| ¡  S S t d|› ¡ W W |rc| ¡  |rk| ¡  dS dS  ty™ }	 z!t 	d|› d|	› ¡ W Y d}	~	W |r‹| ¡  |r“| ¡  dS dS d}	~	ww |r | ¡  |r§| ¡  w w )zä
        Get bot configuration from cluster database.
        
        Args:
            business_id: Business ID
            bot_id: Bot ID
            
        Returns:
            Bot configuration dictionary or None
        Nr   Tr*   Ú_botszA
            SELECT bot_id, bot_name, agent_id
            FROM `z>`
            WHERE bot_id = %s AND is_active = 1
            r,   Úbot_nameÚagent_id)r,   rH   rI   u&   ðŸ¤– Loaded bot configuration - Name: z, ID: u5   âš ï¸ No active bot configuration found for Bot ID: u0   âŒ Error fetching bot configuration for Bot ID r/   r0   )
r   r-   r,   r%   r1   Ú
table_namer6   r7   Ú
bot_configr&   r   r   r   Úget_bot_configurationŸ   sZ   

þý	
ÿ÷ÿúÿ€ú
ÿz-BotConfigurationService.get_bot_configurationc              
   Ã   sÂ  z¹t  ¡ }|  |¡I dH }|r|d du s|d du r/t d|› d¡ ddddtjdœW S |\}}ddl}g }| |  	||¡¡}| 
d|f¡ | |  |¡¡}	| 
d	|	f¡ |jd
d„ |D ƒddiŽI dH }
t|
d tƒss|
d nd}t|
d tƒs€|
d nd}|s™t d|› d¡ dd|||p•tjdœW S t  ¡ |  ¡ }t d|d›d¡ || dd¡|||p·tjdœW S  tyà } zt d|› d|› ¡ ddddtjdœW  Y d}~S d}~ww )a\  
        Get complete bot configuration by DID number - OPTIMIZED for separate databases.
        All database operations run in thread pool to avoid blocking event loop.
        
        Args:
            did_number: DID number to lookup
            
        Returns:
            Dictionary containing bot configuration and system message
        Nr   é   r.   z, using default configurationzDefault Assistant)rK   rH   r-   r,   Úcompany_namerK   rN   c                 S   s   g | ]\}}|‘qS r   r   )Ú.0Ú_Útaskr   r   r   Ú
<listcomp>ÿ   s    zHBotConfigurationService.get_bot_configuration_by_did.<locals>.<listcomp>Úreturn_exceptionsTu.   âš ï¸ No bot configuration found for Bot ID: z, using defaultu    âš¡ Bot configuration loaded in z.2fz secondsÚnameÚ	Assistantu,   âŒ Error getting bot configuration for DID r/   )r   ÚnowrD   r   r5   r   ÚCOMPANY_NAMEr@   Úcreate_taskÚ_get_bot_config_asyncÚappendÚ_get_company_name_asyncÚgatherÚ
isinstanceÚ	ExceptionÚtotal_secondsr   Úgetr#   )r   r(   Ú
start_timer7   r,   r-   r@   ÚtasksÚbot_taskÚcompany_taskÚresultsrK   rN   Ú
total_timer&   r   r   r   Úget_bot_configuration_by_didÓ   s`   €û û
ûû€þz4BotConfigurationService.get_bot_configuration_by_didc                 ƒ   s<   ddl }ddl}‡ ‡‡fdd„}| ¡ }| d|¡I dH S )z-Async version of bot configuration retrieval.r   Nc                      s   ˆ  ˆˆ ¡S r;   )rL   r   ©r,   r-   r   r   r   Ú_sync_get_bot_config,  s   zKBotConfigurationService._get_bot_config_async.<locals>._sync_get_bot_config)r@   Úmysql.connectorrA   rB   )r   r-   r,   r@   r    ri   rC   r   rh   r   rY   '  s   €z-BotConfigurationService._get_bot_config_asyncc                 ƒ   r9   )z(Async version of company name retrieval.r   Nc                      r:   r;   )rF   r   ©r-   r   r   r   Ú_sync_get_company_name7  r>   zOBotConfigurationService._get_company_name_async.<locals>._sync_get_company_namer?   )r   r-   r@   rl   rC   r   rk   r   r[   3  s
   €z/BotConfigurationService._get_company_name_asyncc              
   C   s  dddœ}z%|   d¡}| ¡ }| d¡ | ¡  | ¡  | ¡  d|d< t d¡ W n tyD } zt d|› ¡ W Y d}~nd}~ww z&|   d	¡}| ¡ }| d¡ | ¡  | ¡  | ¡  d|d	< t d
¡ W |S  ty† } zt d|› ¡ W Y d}~|S d}~ww )z–
        Test connections to both master and cluster databases.
        
        Returns:
            Dictionary with connection test results
        F)r   r   r   zSELECT 1Tu)   âœ… Master database connection successfulu'   âŒ Master database connection failed: Nr   u*   âœ… Cluster database connection successfulu(   âŒ Cluster database connection failed: )	r'   r1   r2   r3   r4   r   r   r^   r#   )r   re   r%   r1   r&   r   r   r   Útest_database_connections>  s:   


€ÿ

ý€ýz1BotConfigurationService.test_database_connectionsN)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ústrr'   r   Úintr8   rD   rF   r   r   rL   rg   rY   r[   Úboolrm   r   r   r   r   r	      s    ,
"+4"Tr	   )rq   rj   r    r   ÚloggingÚtypingr   r   r   r   r$   r   Úservices.log_utilsr   Ú	getLoggerrn   Úloggerr	   Úbot_configuration_servicer   r   r   r   Ú<module>   s    
  
X