U
    }_i2                     @   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edddZeee dd	d
Z	edddZ
eee dddZeeeeeef  dddZeeeef dddZeeeeeef  dddZeee dddZeeef d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 )NZdevvoicelabs_masterT)hostZdatabaseuserpasswordcharsetZ
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   sh   z(|dkr| j n| j}tjjf |}|W S  tk
rb } ztd| d|   W 5 d}~X Y nX dS )z
        Get database connection for master or cluster database.
        
        Args:
            database_type: 'master' or 'cluster'
            
        Returns:
            Database connection
        masteru   ❌ Error connecting to z database: N)r   r   mysqlZ	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}zz| d}|jdd}d}|||f | }|rz|d }|d }td| d	| d
|  ||fW W fS td|  W W NdS W nB tk
r } z$t	d| d|  W Y W dS d}~X Y nX W 5 |r|   |r|   X dS )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 : 
closer#   cursorexecutefetchoner   r   warningr   r   )	r   r$   r!   r.   queryresultr(   r)   r"   r   r   r   get_bot_id_by_did>   s,    

 z)BotConfigurationService.get_bot_id_by_did)r$   c                    s0   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
     S N)r4   r   r$   r   r   r   _sync_get_bot_idn   s    zIBotConfigurationService.get_bot_id_by_did_async.<locals>._sync_get_bot_idasyncioget_event_looprun_in_executor)r   r$   r9   r7   loopr   r6   r   get_bot_id_by_did_asyncj   s    z/BotConfigurationService.get_bot_id_by_did_async)r)   r%   c              
   C   s   d}d}zzz| d}|jdd}d}|||f | }|rh|d }td| d|  |W W fS td	|  W W NdS W nB tk
r } z$t	d
| d|  W Y W dS d}~X Y nX W 5 |r|   |r|   X dS )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+   r,   )r   r)   r!   r.   r2   r3   r>   r"   r   r   r   get_business_name_by_idt   s*    


 z/BotConfigurationService.get_business_name_by_id)r)   r(   r%   c           
   
   C   s  d}d}zz| d}|jdd}| d}d| d}|||f | }|r|d |d	 |d
 d}td|d	  d|  |W W fS td|  W W NdS W nB tk
r }	 z$t	d| d|	  W Y W dS d}	~	X Y nX W 5 |r |   |r|   X dS )z
        Get bot configuration from cluster database.
        
        Args:
            business_id: Business ID
            bot_id: Bot ID
            
        Returns:
            Bot configuration dictionary or None
        Nr   Tr&   Z_botszA
            SELECT bot_id, bot_name, agent_id
            FROM `z>`
            WHERE bot_id = %s AND is_active = 1
            r(   bot_nameagent_id)r(   r@   rA   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+   r,   )
r   r)   r(   r!   r.   Z
table_namer2   r3   
bot_configr"   r   r   r   get_bot_configuration   s6    


 z-BotConfigurationService.get_bot_configurationc              
      s  zzt  }| |I dH }|r8|d dks8|d dk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s|
d nd}t|
d ts|
d nd}|s8td| d dd|||p0tjdW S t  |  }td|dd ||dd|||pvtjdW S  tk
r } z0td| d|  ddddtjd W Y S d}~X Y nX dS )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)rB   r@   r)   r(   company_namerB   rE   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   nowr=   r   r1   r   COMPANY_NAMEr9   create_task_get_bot_config_asyncappend_get_company_name_asyncgather
isinstance	Exceptiontotal_secondsr   getr   )r   r$   Z
start_timer3   r(   r)   r9   tasksZbot_taskZcompany_taskresultsrB   rE   Z
total_timer"   r   r   r   get_bot_configuration_by_did   sZ     


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 r5   )rC   r   r(   r)   r   r   r   _sync_get_bot_config,  s    zKBotConfigurationService._get_bot_config_async.<locals>._sync_get_bot_config)r9   mysql.connectorr:   r;   )r   r)   r(   r9   r   r\   r<   r   r[   r   rP   '  s
    z-BotConfigurationService._get_bot_config_asyncc                    s0   ddl } fdd}| }|d|I dH S )z(Async version of company name retrieval.r   Nc                      s
     S r5   )r?   r   r)   r   r   r   _sync_get_company_name7  s    zOBotConfigurationService._get_company_name_async.<locals>._sync_get_company_namer8   )r   r)   r9   r_   r<   r   r^   r   rR   3  s    z/BotConfigurationService._get_company_name_async)r%   c              
   C   s  ddd}zJ|  d}| }|d |  |  |  d|d< td W n2 tk
r } ztd|  W 5 d}~X Y nX zJ|  d	}| }|d |  |  |  d|d	< td
 W n4 tk
r } ztd|  W 5 d}~X Y nX |S )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#   r.   r/   r0   r-   r   r   rU   r   )r   rY   r!   r.   r"   r   r   r   test_database_connections>  s0    


"

"z1BotConfigurationService.test_database_connectionsN)r   )__name__
__module____qualname____doc__r   strr#   r   intr4   r=   r?   r   r   rC   rZ   rP   rR   boolr`   r   r   r   r   r	      s   ,
+4Tr	   )rd   r]   r   r   loggingtypingr   r   r   r   r    r   services.log_utilsr   	getLoggerra   loggerr	   bot_configuration_servicer   r   r   r   <module>   s   
  X