
    4ʜhL                     N   d dl mZ d dlmZmZ d dlmZmZmZm	Z	 d dl
Z
d dlm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 d d
lm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   e
jB                  e"      Z# edgd      Z$	 	 	 	 d0dede%de%de&de&f
dZ'dede%dejP                  fdZ)dede*deejP                     fdZ+dede*deejP                     fdZ,d1dedejZ                  d ee*   dejP                  fd!Z.dede%dej^                  dejP                  fd"Z0dede%de1fd#Z2ded$e%deejP                     fd%Z3dede%d&e%dejP                  fd'Z4dede%d(e&deejP                     fd)Z5dede%dee*e	f   fd*Z6dede*fd+Z7dedeee*e	f      fd,Z8d2d-Z9d.ejt                  defd/Z;y)3    )Session)HTTPExceptionstatus)ListOptionalDictAnyN)CryptContext)datetime	timedelta)get_speech_to_text)
CallSourceCronJobStatus)get_call_recording_public_url)get_setting_value)modelsschemas   )get_department)send_welcome_emailbcryptauto)schemes
deprecateddbskiplimitorder_by_statusorder_by_namec                    | j                  t        j                  t        j                  j                        j                  t        j                  t        j                  j                  t        j                  j                  k(        j                  t        j                  j                  j                         t        j                  j                        j                  |      j                  |      }|j                         }g }|D ]G  \  }}	|j                  j!                         }
|
j#                  dd       |	|
d<   |j%                  |
       I |S )a  
    Get all advisors with optional ordering by status and name.
    
    Args:
        db: Database session
        skip: Number of records to skip
        limit: Maximum number of records to return
        order_by_status: If True, order by status (available first)
        order_by_name: If True, order by full name
        
    Returns:
        List of advisors with the specified ordering
    _sa_instance_stateNaccount_status)queryr   AdvisorUserr"   joinuser_ididorder_byr   desc	full_nameoffsetr   all__dict__copypopappend)r   r   r   r   r   r#   resultsadvisorsadvisorr"   advisor_dicts              N/var/www/html/DP/alpha_backend/app/advisor_service/services/advisor_service.pyget_advisorsr7      s    , HHV^^V[[%?%?@	fkk6>>11V[[^^C	D	&..'',,.0H0H	I		u	 
 iikG H#*'',,.-t4)7%&%	 $+ O    
advisor_idreturnc                 <   | j                  t        j                        j                  t        j                  j                  |k(        j                  t        j                  j                  j                               j                         }|st        dd      |S )N  Staff member not foundstatus_codedetail)
r#   r   r$   filterr(   r)   r+   ascfirstr   )r   r9   r4   s      r6   get_advisorrD   Q   sn    hhv~~&--fnn.?.?:.MNWWX^XfXfXpXpXtXtXvw}}G4LMMNr8   emailc                     | j                  t        j                        j                  t        j                  j                  |k(        j                         S N)r#   r   r$   rA   rE   rC   )r   rE   s     r6   get_advisor_by_emailrH   W   s8    88FNN#**6>>+?+?5+HIOOQQr8   phone_numberc                     | j                  t        j                        j                  t        j                  j                  |k(        j                         S rG   )r#   r   r$   rA   rI   rC   )r   rI   s     r6   get_advisor_by_phonerK   Z   s8    88FNN#**6>>+F+F,+VW]]__r8   r4   passwordc           
      l   t        | |j                        }|rt        dd      | j                  t        j
                        j                  t        j
                  j                  j                  |j                              j                         }|rt        dd      | j                  t        j                        j                  t        j                  j                  |j                  k(        j                         }|rt        dd      t        | |j                        }|rt        dd      |j                  rt        | |j                         t               }t         j#                  |      }	 t	        j                  |j                  |j                  |j                  ||j$                        }| j'                  |       | j)                          t	        j
                  |j*                  |j                  |j                  |j                  |j,                  |j                  d|j$                        }| j'                  |       | j/                          | j                  t        j
                        j                  t        j
                  j                  |j                  k(        j                         }t1        |j                  |j                  |	      }|S # t2        $ rE}	| j5                          t7        d
t9        |	              t        ddt9        |	             d}	~	ww xY w)z
    Create a new advisor and corresponding user account
    
    Args:
        db: Database session
        advisor: Advisor data
        password: Password for the user account
        
    Returns:
        Created advisor object
      .A staff member with this email already exists.r>   zJA staff member with this name already exists. Please use a different name.z5A staff member with this phone number already exists.)namerE   phonerL   typer   )r'   r+   rE   rI   r   department_idcurrent_scorerR   )	recipientrP   rL   z!Error creating advisor and user:   zFailed to create advisor: N)rH   rE   r   r#   r   r$   rA   r+   ilikerC   r%   rK   rI   rS   r   generate_strong_passwordpwd_contexthashrR   addflushr(   r   commitr   	Exceptionrollbackprintstr)
r   r4   rL   
db_advisordb_usergenerated_passwordhashed_passwordcreated_advisor
email_sentes
             r6   create_advisorri   ]   s    &b'--8J4dee &..)00  &&w'8'89eg  _
 	
 hhv{{#**6;;+<+<+MNTTVG4dee &b'*>*>?J4kll r7001 23!&&'9:O0[++""--&&$
 	w

 ^^JJ''-- -->>!//	

 	z 			 ((6>>299NN  GMM1

%' 	
 (mm""'

  [
1#a&:;6PQTUVQWPX4YZZ[s   9E+K% %	L3.A L..L3c                    t        | |      }|j                  r>|j                  |j                  k7  r%t        | |j                        }|rt        dd      |j                  rt        | |j                         |j                  |j                  |_        |j                  |j                  |_        |j                  |j                  |_        |j                  |j                  |_        |j                  |j                  |_	        |j                  |j                  |_        |j                  |j                  |_
        |j                  }| j                  t        j                        j                  t        j                  j                   |k(        j#                         }|r|j                  |j                  |_
        | j%                          | j'                  |       |S )NrN   rO   r>   )rD   rE   rH   r   rS   r   r+   rI   rT   r   rR   r'   r#   r   r%   rA   r(   rC   r]   refresh)r   r9   r4   rb   existingr'   rc   s          r6   update_advisorrm      s   R,J }}**:*::'GMM:C8hii r7001 $&00
}} "==
'")"6"6
(#*#8#8
 ~~!#NN
(#*#8#8
 ||!,,
  Ghhv{{#**6;;>>W+DEKKMG7<<+||IIKJJzr8   c                 *   t        | |      }|st        dd      |j                  }	 | j                  |       |rj| j	                  t
        j                        j                  t
        j                  j                  |k(        j                         }|r| j                  |       | j                          ddiS # t        $ rO}| j                          t        j                  dt        |              t        ddt        |             d	}~ww xY w)
z
    Delete an advisor and their corresponding user account
    
    Args:
        db: Database session
        advisor_id: ID of the advisor to delete
        
    Returns:
        Message confirming deletion
    r<   r=   r>   messagez8Advisor and associated user account deleted successfullyz!Error deleting advisor and user: rV   zFailed to delete advisor: N)rD   r   r'   deleter#   r   r%   rA   r(   rC   r]   r^   r_   loggererrorra   )r   r9   rb   r'   rc   rh   s         r6   delete_advisorrs      s     R,J4LMM   G[
		* hhv{{+226;;>>W3LMSSUG		'" 			UVV [
8QAB6PQTUVQWPX4YZZ[s   BB: :	DA
DDrS   c                     | j                  t        j                        j                  t        j                  j                  |k(        j                         S rG   )r#   r   r$   rA   rS   r-   )r   rS   s     r6   get_advisors_by_departmentru   	  s8    88FNN#**6>>+G+G=+XY]]__r8   scorec                 n    t        | |      }||_        | j                          | j                  |       |S rG   )rD   rT   r]   rk   )r   r9   rv   rb   s       r6   update_advisor_scorerx     s1    R,J$JIIKJJzr8   is_availablec                    	 | j                  t        j                        j                  t        j                  j                  |k(        j                         }|st        d| d       y|rd|_        nd|_        | j                          | j                  |       |S # t        $ r-}| j                          t        dt        |               d}~ww xY w)a)  
    Update the availability status of an advisor.
    
    Args:
        db: Database session
        advisor_id: ID of the advisor to update
        is_available: True if advisor is available, False otherwise
        
    Returns:
        Updated Advisor object or None if advisor not found
    zAdvisor with ID z
 not foundN10z%Error updating advisor availability: )r#   r   r$   rA   r(   rC   r`   r   r]   rk   r^   r_   ra   )r   r9   ry   r4   rh   s        r6   update_advisor_availabilityr}     s    ((6>>*11&..2C2Cz2QRXXZ$ZL
;<  GN GN 			


7  
5c!fX>?s   A(B +3B 	C((CCc                    	 | j                  t        j                        j                  t        j                  j                  |k(        j                         }t        d|j                   d       |sddddS |j                  dk7  rdd|j                  dS t        j                         }| j                  t        j                        j                  t        j                  j                  |k(  t        j                  j                  |k  t        j                  j                  |k\        j                         }|sdd	|j                  dS |j                  d
k7  rdd|j                  dS dd|j                  dS # t        $ r=}t         j#                  dt%        |              ddt%        |       ddcY d}~S d}~ww xY w)a   
    Check if an advisor is currently available based on their schedule and status
    
    Args:
        db: Database session
        advisor_id: ID of the advisor to check
        
    Returns:
        Dictionary with availability status and details
    z=-=-=-=-=-=-=-=Advisor status: =-=-=-=-=-=-=-=FzAdvisor not foundN)	availablereasonr   r{   zAdvisor is not activez%Advisor is not scheduled at this timer   z*Advisor's schedule status is not availableTzAdvisor is availablez%Error checking advisor availability: zError checking availability: )r#   r   r$   rA   r(   rC   r`   r   r   nowAdvisorScheduler9   shift_period_startshift_period_endadvisor_statusr^   rq   rr   ra   )r   r9   r4   r   current_schedulerh   s         r6   is_advisor_availabler   9  s   >
((6>>*11&..2C2Cz2QRXXZ//?OP"-  >>S "1!..  lln HHV++,V&&11Z?&&99S@&&773>
 UW 	  "A!..  **a/"F*99  ,nn
 	
  
<SVHEF5c!fX>
 	

s7   A7E= :E= B4E= E= -E= =	G2F>8G>Gc                 ,   	 | j                  t        j                        j                  t        j                  j                  dk(        j                         }|r|j                  S dS # t        $ r!}t        dt        |              Y d}~yd}~ww xY w)z
    Get timezone from alpha_settings table
    
    Args:
        db: Database session
        
    Returns:
        str: Timezone string (e.g., 'America/New_York')
    timezoneUTCz'Error fetching timezone from settings: N)
r#   r   AlphaSettingsrA   keyrC   valuer^   r`   ra   )r   timezone_settingrh   s      r6   get_timezone_from_settingsr     s    88F$8$89@@  $$
2

%' 	 *:%%DuD 7Ax@As   A$A) 'A) )	B2BBc           	         	 t        | dd      }t        |      }t        j                         }|t	        |      z   }t        d| d|        | j                  t        j                        j                  t        j                  t        j                  j                  t        j                  j                  k(        j                  t        j                  j                  |k  t        j                  j                  |k\  t        j                  j                   dk(  t        j                  j"                  dk(        j%                         }g }|D ]K  }|j'                  |j                  |j(                  |j*                  |j,                  |j"                  d       M |S # t.        $ r-}t0        j3                  dt5        |              g cY d	}~S d	}~ww xY w)
z
    Get a list of all currently available advisors
    
    Args:
        db: Database session
        
    Returns:
        List of available advisors with their details
    TIMEZONE_OFFSETr|   )hourszCurrent time with offset : r   )r(   rP   rE   rI   r   z"Error getting available advisors: N)r   intr   utcnowr   r`   r#   r   r$   r&   r   r9   r(   rA   r   r   r   r   r-   r1   rP   rE   rI   r^   rq   rr   ra   )	r   
offset_stroffset_hoursutc_nowr   available_advisorsresultr4   rh   s	            r6   get_all_available_advisorsr     sx   +&r+<cB
: //#	55),r#?@
 HHV^^$T&&&&11V^^5F5FF V&&99S@&&773>&&55:%%*	 SU 	  )GMMjj  ' 4 4!..  *  9#a&BC	s   FF 	G'"G	GGc                    t         j                  }t         j                  }t         j                  }d}t	        j
                  |      t	        j
                  |      t	        j
                  |      t	        j
                  |      g}| dz
  }||z   |z   |z   |j                  fdt        |      D               t	        j                  |       dj                  |      S )z!Generate a strong random passwordz#$%&@*!   c              3   H   K   | ]  }t        j                          y wrG   )randomchoice).0_	all_charss     r6   	<genexpr>z+generate_strong_password.<locals>.<genexpr>  s     N6MFMM),6Ms   " )
stringascii_lowercaseascii_uppercasedigitsr   r   extendrangeshuffler&   )length	lowercase	uppercaser   special_charsrL   remaining_lengthr   s          @r6   rX   rX     s     &&I&&I]]FM 	i i fm$	H zI%.>IOONe<L6MNN NN8 778r8   callc           	      `  K   	 | j                   }t        d| d       |t        d| j                          y t        j                  | _        |j                          t        |      }|4t        d|        t        j                  | _        |j                          y t        || j                  t        j                  k(        \  }}}}|4t        d|        t        j                  | _        |j                          y t        d| d       t        d| d       t        d	| d       t        j                  d| d       t        j                  d| d       d
}|r| j                  t        j                  k(  rq|D ]M  }	d}
|	j                  dk(  rd}
n#|	j                  dk(  rd}
n|	j                  dk(  rd}
||
 |	j                    dz  }O t        j                  d|        || _        || _        || _        || _        t        j*                  | _        |j                          |j-                  |        t        d| d       y # t.        $ rS}t        d| j                   dt1        |              t        j                  | _        |j                          Y d }~y d }~ww xY ww)Nz==-=-=-=-=-=-=-=Processing booking intent for Twilio call ID: r   zNo Twilio call ID for call z%Could not get recording URL for call )speaker_labelsz"Failed to get transcript for call z=-=-=-=-=-=-=-=Transcript: z=-=-=-=-=-=-=-=Booking intent: z!=-=-=-=-=-=-=-=Booking datetime: r   zAgent:ABzUser:CzAdvisor: zFormatted transcript:
zG=-=-=-=-=-=-=-=Completed processing booking intent for Twilio call ID: zError processing call r   )twilio_call_idr`   r(   r   RUNNINGbooking_intent_statusr]   r   FAILEDr   sourcer   ULTRAVOXrq   infospeakertext
transcripttwilio_recording_textbooking_intentschedule_datetime	COMPLETEDrk   r^   ra   )r   r   r   recording_public_urlr   r   booking_datetimetranscript_with_speaker_labels#transcript_with_speaker_labels_text	utterancespeaker_namerh   s               r6   process_booking_intentr     s    7,,MnM]]lmn!/y9: &3%:%:"
		<^L'9.9IJK)6)=)=D&IIKWij~  PT  P[  P[  ]g  ]p  ]p  Pp  XqT
N$46T6~6FGH)6)=)=D&IIK+J<GH//?OP12B1C?ST1*_MN5n5E_UV.0+)dkkZ=P=P.P;	'$$+#+L&&#-#*L&&#-#-L3,	GWWX7YY3 < KK12U1VWX?DO%/",!1%2%<%<"
		


4WXfWggvwx &twwir#a&:;%2%9%9"
		sT   J.5I J.A%I J. A"I J.EI J.	J+A	J&!J.&J++J.)r   d   FFrG   )   )<sqlalchemy.ormr   fastapir   r   typingr   r   r   r	   loggingpasslib.contextr
   r   r   app.common.ai_helpersr   app.common.constantsr   r   app.common.twillio_helperr   app.common.utilsr   r   r   
app.commonr   r   department_servicer   !app.common.services.email_servicer   	getLogger__name__rq   rY   r   boolr7   r$   rD   ra   rH   rK   AdvisorCreateri   AdvisorUpdaterm   dictrs   ru   rx   r}   r   r   r   rX   CallsLogr    r8   r6   <module>r      s   " ) , ,  ( ( 4 : C .   & . @			8	$ H:&A !&&
& & 	&
 &rG   RW RS RXfnn5M R`W `C `HV^^<T `^[w ^[)>)> ^[(SV- ^[cicqcq ^[@$w $C $':O:O $TZTbTb $L$[w $[C $[D $[L`7 `3 `4CW `W # c fnn $G $ $D $U]^d^l^lUm $LI
W I
# I
$sCx. I
V7 s &57 5tDcN/C 5p68v 8G 8r8   