o
    ̤gQ                     @   s  d dl m 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
 d dlmZ d dlmZ d dlmZ d d	lmZmZmZmZmZmZ d d
lZd d
lZd d
lZd d
lZd dlmZmZm Z m!Z! d dl"m#Z#m$Z$ d dl%m&Z& d dl'm(Z( d dl m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1 d dl2m3Z3 d dl4m5Z5 d dl6m7Z7 d dl8m9Z9m:Z: e;dZ<G dd dZ=e Z>G dd de#Z?G dd de#Z@e>Adeefd e@d!efd"d#ZBG d$d% d%e#ZCe>Ad&eefd eCd!efd'd(ZDd
S ))    )datetime)OptionalListDict)Session)SQLAlchemyError)text)get_db)User)user)pwd_contextcreate_access_tokenget_password_hashcreate_refresh_tokenverify_refresh_tokengenerate_verification_codeN)	APIRouterDependsHTTPExceptionstatus)	BaseModelEmailStr)send_verification_email)PasswordReset)	timedelta)now)UserReferral)PointTransaction)
UserPoints)settings)NotificationService)create_friendship)get_setting_floatget_setting_int	adimsayarc                   @   sr  e Zd Zedededee fddZedede	dee fddZ
e	
d(dedededee fddZede	fddZededejdefddZedededejdee fddZedededee fddZedede	de	fddZedede	de	dee fddZed)dedededd fd!d"Zededed#edd fd$d%Zededee fd&d'Zd S )*UserServicedbuser_idreturnc              
   C   s   z-t d|  | ttj|k }|r#t d|  |W S t d|  |W S  tyG } zt 	d| dt
|   d }~ww )NzFetching user with id: zFound user with id: zNo user found with id: z#Database error while fetching user : )loggerinfoqueryr
   filteridfirstwarningr   errorstr)r&   r'   r   e r4   !/app/app/services/user_service.pyget_user    s   zUserService.get_useremailc              
   C   s   z1t d|  | ttj|ktjdk }|r't d|  |W S t d|  |W S  t	yK } zt 
d| dt|   d }~ww )NzFetching user with email:    zFound user with email: z!No active user found with email: z,Database error while fetching user by email r)   )r*   r+   r,   r
   r-   r7   r   r/   r0   r   r1   r2   )r&   r7   r   r3   r4   r4   r5   get_user_by_email.   s   "zUserService.get_user_by_emailr   d   skiplimitc              
   C   s:  z|  td }td|  td}|  | }td|  td}|  |||d}g }|D ]@}	t|	j}
d|
vrKd|
v rK|
d |
d< td	|
d
 d|
d  dD ]}||
v rp|
| rp|
| 	 |
|< q^|
|
 q6tdt|  |W S  ty } ztjdt| dd  d }~ww )NzSELECT DATABASE()zConnected to database: zSELECT COUNT(*) FROM userszTotal records in users table: z
                SELECT *
                FROM users
                WHERE status = 1
                ORDER BY id ASC
                LIMIT :skip, :limit
            )r;   r<   
birth_dateZbirthdayzFound user: ID=r.   z, Email=r7   )
created_at
updated_at
last_loginzTotal users found: zError in get_users: Texc_info)executer   scalarr*   r+   dict_mappingdebugget	isoformatappendlen	Exceptionr1   r2   )r&   r;   r<   Zdb_checkZcount_queryZtotal_countr,   resultusersrowZ	user_dictfieldr3   r4   r4   r5   	get_users<   s4   
"zUserService.get_usersc                  C   s    t jt j } dtj| ddS )z,Generate a unique 8-character reference code    )k)stringascii_uppercasedigitsjoinrandomchoices)charsr4   r4   r5   generate_reference_codem   s   z#UserService.generate_reference_coder   c           	      C   s,  zz	 t  }| ttj|k }|snqt|jt|j	|j
|j|j|j|j|j|j||jd|jd}| | |   | | |jrx| ttj|jk }|rxt|j|jd}| | |   ddlm} |j| |j|jdd |W S  ty } ztd	t|  |    d }~ww )
NTi'  )r7   password
first_name	last_name
phone_codephonegenderr=   profile_imagereference_codereference_code_useddaily_step_goalcountry_code)referrer_user_idreferred_user_idr   )friendship_servicepending)r'   	friend_idr   zError creating user: ) r%   r\   r,   r
   r-   rd   r/   r7   r   r]   r^   r_   r`   ra   rb   r=   rc   re   rg   addcommitrefreshr   r.   app.servicesrj   r!   rL   r*   r1   r2   rollback)	r&   r   rd   existsdb_userZreferrerreferralrj   r3   r4   r4   r5   create_users   s`   


zUserService.create_userc              
   C   s   zO|  ttj|k }|sW d S |jr#|j \}}||_||_|j	r*|j	|_	|j
r1|j
|_
|jr8|j|_|jr?|j|_t |_|   | | |W S  tyj } ztdt|  |    d }~ww )NzError updating user: )r,   r
   r-   r.   r/   	full_namesplitr^   r_   r7   ra   rf   rc   r   utcnowr?   rn   ro   rL   r*   r1   r2   rq   )r&   r'   r   rs   r^   r_   r3   r4   r4   r5   update_user   s4   

zUserService.update_userc              
   C   s   z3t d|  t| |}|st d| d W d S d|_t |_| 	  t d|  |W S  t
yQ } zt d| dt|  |    d }~ww )NzDeleting user with id: zNo active user found with id: z for deletionr   z#Successfully deleted user with id: z#Database error while deleting user r)   )r*   r+   r%   r6   r0   r   r   rx   r?   rn   r   r1   r2   rq   )r&   r'   rs   r3   r4   r4   r5   delete_user   s"   
zUserService.delete_usernew_passwordc                 C   sb   t | |}|sddlm}m} ||jddt|}||_|   | 	| t
d|  |S )zG
        Reset the password for the user with the given email.
        r   )r   r   User not foundstatus_codedetailz(Password updated successfully for user: )r%   r9   fastapir   r   HTTP_404_NOT_FOUNDr   r]   rn   ro   r*   r+   )r&   r7   r{   r   r   r   Zhashed_passwordr4   r4   r5   reset_password   s   
zUserService.reset_passwordr]   c           
   
   C   sd  zt d|  | ttj|k }|s#t d|  W d S t	||j
s5t d|  W d S |jdkrEt d|  W d S |jd u }t |_| | |   | | t|jd}t|jd}||d|j|j|j|j|jdd	}d
}|r||d< t d tj| |jd|d t d |W S  ty }	 zt jdt|	 dd  d }	~	ww )Nz$Attempting authentication for user: zUser not found with email: zInvalid password for user: r   z"Inactive user attempted to login: )subjectbearer)r.   r7   r^   r_   r   )access_tokenrefresh_token
token_typer   uP   Tebrikler, adimsayar ile birlikte sağlıklı bir yaşamın tadını çıkarın!welcome_messageu)   New Client Login – Welcome Message Sentu   Hoş Geldiniz!)r&   r'   titlemessageu3   NotificationService.send_notification 호출 완료zAuthentication error: TrA   )r*   r+   r,   r
   r-   r7   r/   r0   r   verifyr]   r   r@   r   rm   rn   ro   r   r.   r   r^   r_   rG   r    Zsend_notificationrL   r1   r2   )
r&   r7   r]   r   Zis_new_userr   r   responser   r3   r4   r4   r5   authenticate_user   s\   





zUserService.authenticate_userri   bonus_pointsNc           	      C   s  |  ttj|ktjdk }|r|j}t|d|dd}| | |  t	t	j
|k }|r:| j|7  _nt	||d}| | t|d|dd}| | |  t	t	j
|k }|ri| j|7  _nt	||d}| | d|_tj| |dd	d
| dd |   dS dS )u   
        신규 사용자의 첫 걸음 기록 시, 추천인에게 referral_bonus 지급 및 알림 생성하고, 추천받은 사용자에게도 signup bonus 지급합니다.
        Freferral_bonusz0Referral bonus awarded upon first step recordingr'   transaction_typeamountdescriptionr'   total_pointszBReferral bonus awarded upon first step recording for referred userTZaward_referral_pointu(   Tebrikler! Referans Bonusu Kazandınız!u-   Arkadaşınızın ilk adım kaydı sayesinde u    puan bonus kazandınız.)r'   Z
notif_typer   r   N)r,   r   r-   ri   awardedr/   rh   r   rm   r   r'   r   r    Zcreate_notificationrn   )	r&   ri   r   rt   referrer_idpoint_txuser_points_recordZpoint_tx_referredZreferred_points_recordr4   r4   r5   award_referral_bonus8  sT   





z UserService.award_referral_bonusearned_pointsc              	   C   s2  |  ttj|k }|r|jnd}t| d|}t| d|}t| d|}d}|}	||kr|  ttj	|	k }
|
s>nU|
j
}t||d  ||d   }|dkrt|d|d	| d
| dd}| | |  ttj|k }|r~| j|7  _nt||d}| | |}	|d7 }||ks.|   dS )u   
        Referred user'ın kazandığı adım puanlarının belirli yüzdesini, 
        referral chain boyunca (0.5% ve sonrasında decay uygulanarak) her seviye için dağıtır.
        N REFERRAL_DIRECT_BONUS_PERCENTAGEREFERRAL_MAX_LEVELREFERRAL_CHAIN_DECAYr8   r:   r   referral_chainzReferral bonus (level z) from user z daily points.r   r   )r,   r
   r-   r.   r/   rg   r"   r#   r   ri   rh   intr   rm   r   r'   r   rn   )r&   ri   r   r   rg   Zbonus_percentageZ	max_levelZdecaylevelcurrent_user_idrt   r   r   r   r   r4   r4   r5   award_referral_chain_bonusq  sD   


 z&UserService.award_referral_chain_bonusc              
   C   sh   z|  tjtjtjdk }dd |D }|W S  ty3 } ztj	dt
| dd  d }~ww )Nr8   c                 S   s   g | ]	}|j |jd qS )r.   rd   r   ).0rO   r4   r4   r5   
<listcomp>  s    z6UserService.get_all_referral_codes.<locals>.<listcomp>zError fetching referral codes: TrA   )r,   r
   r.   rd   r-   r   allrL   r*   r1   r2   )r&   Zreferral_codesrM   r3   r4   r4   r5   get_all_referral_codes  s    z"UserService.get_all_referral_codes)r   r:   )r:   )__name__
__module____qualname__staticmethodr   r   r   r
   r6   r2   r9   r   r   rQ   r\   user_schemasZ
UserCreateru   Z
UserUpdatery   rz   r   r   r   r   r   r4   r4   r4   r5   r%      sT    0;"A84r%   c                   @      e Zd ZU eed< dS )RefreshTokenRequestr   N)r   r   r   r2   __annotations__r4   r4   r4   r5   r        
 r   c                   @   r   )ForgotPasswordRequestr7   N)r   r   r   r   r   r4   r4   r4   r5   r     r   r   z/forgot-passwordreqr&   c                 C   sh   t || j}|sttjddt }t|j|d}|	| |
  t| j|s0ttjddddiS )Nz"User with provided email not foundr}   )r'   
reset_codez!Failed to send verification emailr   z/Reset code has been sent to your email address.)r%   r9   r7   r   r   r   r   r   r.   rm   rn   r   HTTP_500_INTERNAL_SERVER_ERROR)r   r&   r   r   reset_recordr4   r4   r5   forgot_password  s    
r   c                   @   s   e Zd ZU eed< eed< dS )VerifyResetCodeRequestr7   r   N)r   r   r   r   r   r2   r4   r4   r4   r5   r     s   
 r   z/verify-reset-codec                 C   s   t || j}|sttjdd|ttj	|j
ktj| jktj  }|s2ttjdd|jtdd }t }td|j d| d|  ||kr^d	|_|  ttjd
d|jdkrjttjddd	|_|  ddiS )a$  
    Verifies the provided reset code for the given email.
    
    If verification succeeds:
      - Checks if the reset record is still valid and not expired.
      - If expired, marks it as used (is_valid = 0) and raises an error.
      - If valid, marks it as used to prevent re-use.
    r|   r}   zInvalid reset code
   )minuteszReset record created_at: z, expiry_time: z, current_time: r   zReset code expiredr8   z Reset code has already been usedr   z Reset code verified successfully)r%   r9   r7   r   r   r   r,   r   r-   r'   r.   r   order_byr>   descr/   HTTP_400_BAD_REQUESTr   r   r*   r+   is_validrn   )r   r&   r   r   Zexpiry_timecurrent_timer4   r4   r5   verify_reset_code  sJ   



r   )Er   typingr   r   r   sqlalchemy.ormr   Zsqlalchemy.excr   
sqlalchemyr   app.db.sessionr	   app.models.userr
   Zapp.schemasr   r   Zapp.core.securityr   r   r   r   r   r   uuidloggingrY   rU   r   r   r   r   r   pydanticr   r   Zapp.services.email_servicer   app.models.password_resetr   r   app.core.timer   Zapp.models.user_referralr   Zapp.models.point_transactionr   Zapp.models.user_pointsr   app.core.configr   Z!app.services.notification_servicer    Zapp.services.friendship_servicer!   Zapp.services.admin_servicer"   r#   	getLoggerr*   r%   routerr   r   postr   r   r   r4   r4   r4   r5   <module>   sb    
   